Incrementing value in a Map (JAVA) - java

I'm having a problem with this home work assignment. I can handle the syntax, but not the logic. Could you provide me some tips.
What I'm trying to achieve is that the add method would increase the amount of products by using the increaseAmount method. Now it resets the value of amount to "1" every time I call the method. What makes this complicated is that I'm not allowed to use any other private variables than already used.
private Map<String, Purchase> shoppingCart = new HashMap<String, Purchase>();
public void add (String product, int price) {
Purchase purchase = new Purchase (product, 1, price);
//the line abowe returns the value back to 1 which I don't want.
if(shoppingCart.containsKey(product)) {
shoppingCart.put(product, purchase);
purchase.increaseAmount();
}
else {
shoppingCart.put(product, purchase);
The product constructor:
public Ostos(String product, int amount, int price) {
Code for the increaseAmount method:
private int amount;
public void increaseAmount() {
this.amount = (this.amount + 1);

Don't create a new purchase at the beginning only create it if it's not already there
public void add (String product, int price) {
if(shoppingCart.containsKey(product)) {
Purchase purchase = shoppingCart.get(product);
purchase.increaseAmount();
//You might have to put the purchase back into the cart I'm not sure
}
else {
Purchase purchase = new Purchase (product, 1, price);
shoppingCart.put(product, purchase);
}

You have to retrieve the value from shoppingCart and then increment the amount. You're never calling shoppingCart.get, so you're replacing the value each time by blindly putting the new purchase object into the map.

Related

Increasing value of an object if it's already in a map

Every time when a product is added to shoppingBasket if its already in map basket it should increase it value amount by 1. But it doesn't for some reason. Is it because every time im adding a product to map i'm creating a new purchases? I can't figure it out.
public void add(String product, int price) {
Purchases buy = new Purchases(product, 1, price);
if(!basket.containsKey(product)) {
basket.put(product, buy);
} else {
buy.increaseAmount();
}
/
public void increaseAmount() {
this.amount+= 1;
}
/
public class Main {
public static void main(String[] args) {
ShoppingBasket basket = new ShoppingBasket();
basket.add("milk", 3);
basket.print();
System.out.println("basket price: " + basket.price() +"\n");
basket.add("buttermilk", 2);
basket.print();
System.out.println("basket price: " + basket.price() +"\n");
basket.add("milk", 3);
basket.print();
System.out.println("basket price: " + basket.price() +"\n");
basket.add("milk", 3);
basket.print();
System.out.println("basket price: " + basket.price() +"\n");
}
}
/
import java.util.HashMap;
import java.util.Map;
public class ShoppingBasket {
private Map<String,Purchases> basket;
public ShoppingBasket() {
this.basket = new HashMap<String,Purchases>();
}
public void add(String product, int price) {
Purchases buy = new Purchases(product, 1, price);
if(!basket.containsKey(product)) {
basket.put(product, buy);
} else {
buy.increaseAmount();
}
}
public int price() {
int price = 0;
for(Purchases item : basket.values()) {
price += item.price();
}
return price;
}
public void print() {
Map<String, Integer> test = new HashMap<String,Integer>();
for(Purchases item : basket.values()) {
test.put(item.product(), item.amount());
}
for(String key : test.keySet()) {
Integer value = test.get(key);
String complete = key + ": " + value;
System.out.println(complete);
}
}
}
/
public class Purchases {
private String product;
private int amount;
private int unitPrice;
public Purchases(String product,int amount, int unitPrice) {
this.product = product;
this.amount = amount;
this.unitPrice = unitPrice;
}
public int price() {
return this.amount * this.unitPrice;
}
public void increaseAmount() {
this.amount+= 1;
}
public String toString() {
return "" + this.amount;
}
public int amount() {
return this.amount;
}
public String product() {
return this.product;
}
}
In your else black, you need to retrieve the Purchase object from the map. Then call increaseAmount on the object retrieved.
public void add(String product, int price) {
Purchases buy = new Purchases(product, 1, price);
if(!basket.containsKey(product)) {
basket.put(product, buy);
} else {
buy = basket.get(product); <--retrieve it
buy.increaseAmount(); <--increment amount
}
}
code is not adding purchase to map if key is already there, add map.put in else part
public void add(String product, int price) {
Purchases buy = new Purchases(product, 1, price);
if(!basket.containsKey(product)) {
basket.put(product, buy);
} else {
buy.increaseAmount();
basket.put(product, buy);
}
}
Purchases buy = new Purchases(product, 1, price);
See the new? You're making a new object here, hence the name. You then increment the product count on this new object and promptly toss the only variable that refers to this new object (your buy variable) in the garbage, because that's what happens with all local variables when a method ends: The variable goes away. With that, nothing refers to this brand new Purchases instance and thus it'll eventually be garbage collected.
You want to query for the actual object that was made earlier and stored in that map, then increment the product count on that.
In your code, you make a new Purchases instance no matter what happens, and then map the given string to this newly created purchases object only if the string isn't already in your map. This is no good. You want to create a new purchases instance only if it isn't already in the map, otherwise you want to fetch the existing instance of Purchases.
You could do this:
Purchases buy;
if(!basket.containsKey(product)) {
basket.put(product, buy = new Purchases(product, 1, price));
} else {
basket.get(product).increaseAmount();
}
But this is inefficient, 'ugly' (kinda hard to maintain), and outright broken if this is a concurrent hashmap. Much better is to act-then-check instead:
basket
.computeIfAbsent(product, k -> new Purchases(product, 0, price))
.increaseAmount();
This code does just what it says: It will compute the requisite value, but only if there is no key/value mapping yet. So, IF product is in the map, you just get the Purchases instances associated with it and we move immediately on to .increaseAmount(). But if it is not, the code new Purchases(product, 0, price) is executed and whatever that resolves to is used as the value (So, it's like .put(product, new Purchases(...)), except the new part is only run if that item wasn't in the map already. There's a k -> in there because [A] it's a closure, it's code that is sent to the computeIfAbsent method and is only actually run if needed, and [B] you get the key passed along. Here, not needed, you already have this (variable product), but you can imagine you invoked perhaps basket.computeIfAbsent(some.complex().calculation(), ...., that's why it's there.
You then call increaseAmount() on whatever you get. Hence why this code starts out with an amount of 0: Because it'll be increment to 1 immediately afterwards.
This is because you increase the amount in the new Purchases object which is not in the map.
Let's do code analysis:
[Map State] EMPTY
You put one Purchases object with product's name/key "milk" inside the map:
public void add(String product, int price) {
Purchases buy = new Purchases(product, 1, price);
if(!basket.containsKey(product)) {
// Executed
basket.put(product, buy);
} else {
buy.increaseAmount();
}
}
As you probably know the code found in the if block is executed - Adds the object inside buy to the map.
[Map State] { "milk", PurchasesObject1 }
Now you are trying again to put a NEW Purchases object whose product's/key value is "milk" again into the map. As you probably know, the else block will be executed, Because Purchases object with key "milk" already exists in the map.
What happens in the else block is that you increase the value of amount of the NEW local object you've just created inside the method, which is not even in the map at all, so once the add() method finishes its execution, the object you've created becomes garbage that needs to be collected by the garbage collector.
Solution?
Sure. Just retrieve the object with the same key and do what you wanted on it.
public void add(String product, int price) {
Purchases buy = new Purchases(product, 1, price);
if(!basket.containsKey(product)) {
// Executed
basket.put(product, buy);
} else {
basket.get(product).increaseAmount();
}
}

Updating the value of an object in an arraylist

This problem has been bugging me for the last while.. i cant seem to be able to update the stock value of the vehicle that i'm selling. I understand how to search the array and locate the model that the user is looking for but i don't understand how to update the number of that specific model vehicle that are in stock. which is going to be stock - 1 after a purchase.
I have both basic getters and setters for model and stock variables in the Vehicles superclass
Any help is appreciate!
Below is the method of purchasing a car from the driver class
public void purchaseCar()
{
Scanner scan = new Scanner(System.in);
String model, ans;
System.out.println("****Car Purchase Page****");
System.out.println("Enter the model of car you're looking to purchase");
model = scan.nextLine();
for (Vehicles v : list) {
if (v.getmodel().equals(model))
{
System.out.println("Is this the model you want to purchase?");
ans = scan.nextLine();
if (ans.equals("yes")) {
System.out.println("Okay! Your order is being processed");
Vehicles.setStock() = stock - 1;
}
else {
System.out.println("not working");
}
}
}
}
You're almost there.
Change:
Vehicles.setStock() = stock - 1;
to:
v.setStock(v.getStock() - 1);
As clarification, this is the same as:
int stock = v.getStock(); // Get the current stock value of 'v'
int newStock = stock - 1; // The new stock value after the purchase
v.setStock(newStock); // Set the new stock value
You are not invoking the Vehicles.setStock() on the object you want to update. And in addition this method doesn't receive any parameter to update the new stock.
You should call the method on the instance you want to update passing it the new value of the stock.
Try this
v.setStock(v.getStock() - 1);
If it seems strange to you to use the v.getStock() to build the parameter you can create a new method within your vehicle class.
class Vehicles{
int stock;
public void consumeOne(){
stock = stock -1;
}
}
And then you can call this new method in the for statement
for (Vehicles v : list) {
if (v.getmodel().equals(model)){
ans = scan.nextLine();
if (ans.equals("yes")) {
v.consumeOne();
}else {
System.out.println("not working");
}
}
}

is this the correct use of aggregation

I want to simulate a cash register system. At the end of the transaction, the receipt would be displayed on the monitor. I've created a class called Receipt, it contains info about items purchased by the customer, subtotal, and customer's name. So, in the Receipt class, I created an ArrayList of product and a buyer object as instance variables. The toString() function would return a nice formatted string.
I am not sure if I should use ArrayList as an instance variable and I don't know if aggregation is the best choice here.
import java.util.ArrayList;
public class Receipt {
private ArrayList<Product> purchased_products;
private double total_price;
private double total_with_tax;
private Buyer buyer;
public Receipt(Buyer buyer, ArrayList<Product> purchased_products,
double total_price, double total_with_tax) {
this.purchased_products = new ArrayList<>(purchased_products);
this.total_price = total_price;
this.buyer = buyer;
this.total_with_tax = total_with_tax;
}
#Override
public String toString() {
String content = "Receipt: \nConvenience Store\n";
content += "Balance Summary:\n";
for (Product product : purchased_products) {
content += product + "\n";
}
content += String.format("%d Subtotals: $%.2f\nAmount Paid: $%.2f\n", purchased_products.size(), total_price,
total_with_tax);
content += buyer.toString() + "\n";
content += "Thank you for shopping with us. Have a wonderful day!\n";
return content;
}
}
Everything looks fine and you are doing it correct almost.
A small correction in constrctor is you need not to have a new array list again.
Just
this.purchased_products = purchased_products;
Is enough.

How would I allow multiple users in an array to have separate access to a variable?

I understand the title is quite confusing so I'll clarify here.
The following is an extremely simple bank class I slapped together that takes the users name and balance and has deposit and withdraw classes.
public class Bank {
String user;
int balance = 0;
int pin;
public void setup (String n,int p)
{
user = n;
pin = p;
}
public void withdraw (int amount)
{
balance -= amount;
}
public void deposit (int amount)
{
balance += amount;
}
public String toString ()
{
return String.format("User: %s\nBalance: %s",user,balance);
}
}
Now. Here is my qualm. The following is another simple class I made to make use of the Bank class. I've tried HashMaps, Arrays and I'm sure I'm just missing a basic principle. This isn't for a class I would just like to know how to do the following:
I want to be able to create different users (I'm sure I'd have to use (like I have) a HashMap or ArrayList) and have EACH user have separate access to the balance variable, so when one person, lets say person X with pin 1234 withdraws funds, ONLY their funds are withdrawn.
I know I can just use a HashMap and set it up like
HashMap <String, Integer> HM = new HashMap <String, Integer> ();
HM.put("User",0)
where user is the name and 0 is the balance.
I can easily update different users balances, but this seems counterintuitive.
import java.lang.reflect.Array;
import java.util.*;
public class BankDriver {
public static void main (String [] args)
{
boolean quit = false;
Bank b = new Bank ();
Scanner sc = new Scanner (System.in);
do {
System.out.println("1: Create account\2: Quit");
int input = sc.nextInt();
switch (input)
{
case 1:
b.setup("Name",1234);
System.out.println(b.toString());
break;
case 2:
quit = true;
break;
}
}while(!quit);
System.out.println("Exiting.");
}
}
How would YOU accomplish this?
AGAIN. I know I can do it in different ways, but I was curious if I could accomplish it this way.
The object oriented design that you are using is not very good for what you are trying to achieve. If you want to have access for each client of the bank, you should create a Client class (or Account) with its getters and setters like this:
Also, I changed your integers to doubles
public class Client{
public int pin;
public String name;
public double amount;
public Client(String name, double amount, int pin){
this.name = name;
this.amount = amount;
this.pin = pin;
}
public String getName(){
return name;
}
public int getPin(){
return pin;
}
public void changePin(int newPin){
this.pin = newPin;
}
public void withdraw (double amount)
{
this.amount -= amount;
}
public void deposit (double amount)
{
this.amount += _amount;
}
#Override
public String toString ()
{
return String.format("User: %s\nBalance: %s",this.name,this.amount);
}
}
Now, from your void() you can create all the Clients that you want in any specific data structure. I'll give you an example using a HashMap
HashMap <String, Client> HM = new HashMap <String, Client>();
HM.put("Uri D. Charles", new Client("Uri D. Charles", 100.00, 1234));
HM.put("Luis Lavieri", new Client("Luis Lavieri", 2000.00, 1234));
After that you can manipulate the data structure as you prefer to access that data. I hope this is what you are looking for
First of all create a getter methods for name and pin.
You can create an ArrayList of Bank object and add the bank object to the arraylist each time a user created an account.
Then when the user want to withdraw you then ask them there name and pin and then loop the arraylist while comparing the pin and name of the bank object of the arraylist and the person name and pin that just entered.
If the object was found you can then ask the user how much money to withdraw and call the widraw method.

TreeSets and removing specific unnamed Objects

So I'm writing a program for an assignment where I store Patients into a TreeSet. The problemn I'm having is I have to implement a method to discharge a specefic patient from the TreeSet.
for(int i = 0; i < 10 ; i++){
Random ag = new Random();
int age = ag.nextInt(99) + 1;
Names randomname = Names.getRandom();
String name = randomname.name();
String sex;
if(Math.random() > 0.5)sex = "female";
else sex = "male";
Random sn = new Random();
int serial = sn.nextInt(10000) + 1;
Address randomAddress = Address.getRandom();
String address = randomAddress.name();
Hospital.admitPatient(new Patient(age, name, sex, serial, Birthday.produceBirthday(), address));
}
So Thats how I am looping to get the Patients info and stats for the Patient Object. The admit patient method adds them to the TreeSet.
public static void admitPatient(Patient obj){
if(numofPatients < maxPatients){
patientList1.add(obj);
}
}
The Problem I'm having is withbthe Discharge patient method. Where I don't know what to put in the method
public static void dischargePatient(What do i put here in the driver when i call this method?){
patientList1.remove(w/e i put up there);
}
Since I didn't name the Objects of patients when creating them but just inserted them straight into the TreeSet I'm not sure exactly how to call them when i call the discharge patient method.
As you usually want to work with selected objects (patients) and not the whole list, you need a way to identify them somehow (for example by name or ID).
Since add and remove are similar, your dischargePatient method will be similar as well. Try
public static void dischargePatient(Patient patient) {
patientList1.remove(patient);
}
To retrieve a patient with a certain ID, you may iterate through your set and return it:
public Patient getPatientByID(String id) {
for (Patient patient : patientList1) {
if (patient.getID().equals(id)) {
return patient;
}
}
}
To remove a patient with ID "1234abc", you could do the following:
dischargePatient(getPatientByID("1234abc"));
Using this pattern, you rebuild the functionality of the map datastructure. Thus it might be better to use a Map (e.g. HashMap<>). Code will be reduced to operations like:
Map<String, Patient> patients = new HashMap<>();
patients.put("1234abc", patient1);
patients.remove("1234abc");
Full code for your example:
public static void admitPatient(Patient patient) {
if(numofPatients < maxPatients){
patients.put(patient.getID(), patient);
}
}
public static void dischargePatient(String id) {
patients.remove(id);
}

Categories

Resources