(Java) Varying which object is modified - java

I'm sorry if this is a very obvious question, I guess I simply don't know the proper vocabulary to use to find the answer. My question is: Say I instantiate several objects, and each object has a unique integer that serves as its ID, and I want the user to be able to choose which object to modify by entering the object's ID. How should I go about that?
int ID;
Scanner keyboard = new Scanner(System.in);
Object obj1 = new Object(9897);
Object obj2 = new Object(2817);
System.out.println("Input the ID of the object you wish to modify:");
ID = keyboard.nextInt();
Assume I have a class written so that the objects instantiated in the previous code have their IDs equal to the argument passed to the constructors. Now say in the next line of code I want to change either object 1 or object 2 depending on whether the user inputs 9897 or 2817. How would I go about doing that without using a ton of if statements?

Short answer: you don't. Change your approach, put your instances in a Map<Integer, Object> and then you can look them up by ID.
Map<Integer, Object> map = new HashMap<>();
map.put(9897, new Object());
map.put(2817, new Object());
// ...
int ID = keyboard.nextInt();
Object obj = map.get(ID);

Related

Java - Problems creating a Map inside another Map

I'm trying to create a program that keeps track of a bunch of different Strings, and "ties them together" with the current user's entered name (another String), meaning every person should have their own wallets. I tried to do this using a Map inside another Map, but this is where my brain overloads. How do I tie every wallet to the correct name and then display all of that? The comment in my code gives a good example of it. Here is what I have so far:
Scanner sysin = new Scanner(System.in);
boolean firstTime = true;
Map<String, Set<Long>> walletTracker = new HashMap<String, Set<Long>>();
Map<String, Map<String, Set<Long>>> nameTracker = new HashMap<String, Map<String, Set<Long>>>();
if(!firstTime) {
/* Here it should display every entered name, wallet and time of deposit, like this:
Jack:
JacksWallet:
[12345], [123456], [1234567]
JacksOtherWallet:
[123], [1234]
Jonathan:
JonsWallet:
[12345678]
*/
}
for(int i = 0; i < 1;) {
System.out.print("Enter your name: ");
String name = sysin.nextLine();
System.out.print("Please enter a wallet name: ");
String wallet = sysin.nextLine();
Set<Long> deposits = walletTracker.getOrDefault(name, new HashSet<>());
deposits.add(System.currentTimeMillis());
walletTracker.put(wallet, deposits);
nameTracker.put(name, walletTracker);
System.out.println("You successfully withdrew money from "+ wallet +". Press enter to continue...");
firstTime = false;
String enter = sysin.nextLine();
}
Here's what I found & noticed:
The if(!firstTime) {} block should be within the for loop, so that it actually prints on every iteration.
You attempt to use walletTracker.getOrDefault(name, new HashSet<>());, but the name variable is not the correct variable to use here. You should be using the wallet input variable.
Here is my "print it out" code, that matches your recommended formatting:
nameTracker.forEach((name, wallet) -> {
System.out.println(name);
wallet.forEach((walletName, dates) -> {
System.out.printf("\t%s\n\t\t%s\n",
walletName, Arrays.toString(dates.toArray(new Long[0])));
});
});
Outside of this, the code you used to actually populate the map(s) is correct.
#rzwitserloot Made some good points about using OOP to your advantage, and I would recommend those suggestions as well.
Set<Long> deposits = walletTracker.getOrDefault(name, new HashSet<>());
This returns new HashSet<>() if there is no mapping for name but it does not add that to the map. What you want is .computeIfAbsent, which will just return the mapping that goes with name, but if it is not there at all, it evaluates your lambda and then adds that to the map and then returns that:
Set<Long> deposits = walletTracker.computeIfAbsent(name, k -> new HashSet<>());
That's 'lambda' syntax - you don't write an expression that resolves to a new hashset, you write an expression that resolves to a function that produces a new hashset when provided with the key (which we don't need here, and is equal to name anyway).
Java-esque strategy here is to make a Wallet class at least. In general, once you start putting <> inside `<>, especially if you're 3 levels deep, stop, and start writing classes instead.
That should be a Map<String, Wallet> and a Map<String, Person> or whatnot.

How to assign multiple data types to a single variable in java?

Right now I'm creating a bankApp and I don't have an idea how can I assign e.g. string name; double balance; etc. to a right one int PIN;. There is gonna be many accounts with different PINs and different values assigned to it . I tried making many objects :
perInfo card1 = new perInfo();
card1.PIN = 1994;
card1.balance = 24.68;
card1.isValid = true;
perInfo karta2 = new perInfo();
card2.PIN = 2002;
card2.balance = 522.2;
card2.isValid = false;
but I think it's too much work to do and it'll worsen performance of the app. I also tried making a list
public bApp(int pin, double balance){
this.pin = pin;
this.balance = balance;}
List<bApp> pass = new ArrayList<>();
pass.add(new bApp(1994, 568.45));
pass.add(new bApp(2002, 13866.24));
but it didn't work ,because I couldn't call the PIN to check that if user has provided the right one PIN . Arrays are also not suited for this.
You could use a HashMap for this and use the pin as a key and store the object in the HashMap. This would allow you to access each card using only the pin. However, this would not allow for duplicate pins. I would recommend that you reference each account by a unique ID and check the pin within the object itself.
HashMap<Integer, Account> accounts = new HashMap<Integer, Account>();
accounts.put(12345678, new Account(1994, 568.4));
You can then get the account using the unique ID and check if the pin is correct.
Account acc = accounts.get(uniqueID);
if(acc.pin == enteredPin){
//Whatever you need to do
}
The data structure you are looking for is a Map. Take a look at HashMap and you'll want to key off of whatever value you are using to lookup.
For example if you wanted to lookup a user by pin:
Map<Integer, bApp> passes = new HashMap<>();
passes.put(1994, new bApp(1994, 568.45));
passes.put(2002, new bApp(2002, 13866.24));
I think it would be simpler to just have an array of the different cards, with each pin being set to the array address:
bApp[] cards = new bApp[NUMBER_OF_CARDS];
cards[0] = new bApp(0, 568.45);
// ...
cards[2002] = new bApp(2002, 13866.24);

Naming java objects

So right now, I am making a simple java banking program. It allows you to add a customer and deposit/withdraw funds. Right now, I have 3 classes: Main, Bank, and Customer. Right now I have it so that when you add a customer, it asks you for a name. But right now I am having trouble naming them. I want
Customer to have a username as the object name. For example, if I typed in Bob1789 as the username, the program would do:
Customer Bob1789 = new Customer("Bob1789");
If I typed in randomcustomer123 the program would do:
Customer randomcustomer123 = new Customer("randomcustomer123");
So basically, whatever I type in the box from the scanner, to be passed to the Customer name.
Customer (whatever was typed in the scanner) = new Customer((whatever was typed in the scanner));
I have tried to do this, but java always assumes that the scanner.NextLine() is the Object name.
Is there any way to do this?
You can use a HashMap<String, Customer> for this. This allows you to store name-customer pairs.
HashMap<String, Customer> allCustomers = new HashMap<>();
To create a new customer and put it into the map,
String customerName = scanner.nextLine();
allCustomers.put(customerName, new Customer(customerName));
To get a customer with a specific name, use this:
allCustomers.get("some name");
Don't know why you want to use obj name. Probably you need to use HashMap<String, Customer> where name is the key and value is the object.
Map<String, Customer> map = new HashMap<>();
to add map.put("yourName", obj);
to fetch map.pget("yourName");

Getting the user to name the variables

For my program i want to have it so that the user can name the variables a bit like in a game you would name your charecter/world. I looked it up and couldn't find anywhere that said if this is possible and if so how it is done.
As many others have said, you can't dynamically name variables.
You can however make a Map
It would allow you to create any name for a variable such as "MyTestVar" at runtime and use it as a key in that map to whatever you put:
Map<String, String> myMap = new HashMap<String, String>();
String varName = getVariableNameFromUser();
String value = getValueFromUser();
myMap.put(varName, value);
// ... later
String whatVariableDoYouWantTheValueOf = getVarNameFromUser();
String storedValue = myMap.get(whatVariableDoYouWantTheValueOf);
System.out.println("The value for that is: " + storedValue);
What you can do is create a linked list or an arraylist of some type of object that you create. Your object can then have two properties (or more) where one is the name, and the other is the value. You can then search for an object in your list based on the name, and return the value that you want. This will basically accomplish what you're trying to achieve.
You can't get a user to name a variable. All you can do is allow the user to set the variable's value.
I guess what you mean is something like giving Tags or Labels to Objects. "Variable Names" is a missleading wording for that.
After the User typed in the name string for an obj Object, you could for example use a HashMap<String, Object> to store the user input:
Map<String, Object> tagToObjectStore = new HashMap<String, Object>();
String userInput = "any Tag name";
Object somethingToLabel = ... // TODO
tagToObjectStore.put(userInput, somethingToLabel); // store the user input
// later in code...
Object theStoredObject = tagToObjectStore.get(userInput); // get the stored object
Is that what you are looking for?

Map with multi values

I basically want 2 values on 1 map if possible or something equivalent. I want to store this info
Map<K,V1,V2> sample = new HasMap<K,V1,V2>
(Key - caller) = 26
(value 1 - callee) = 55
(value 2 - seconds) = 550
sample(26,55,550)
the only other way i see how i can do this is
Map(k, arraylist(v2))
having the position in the arraylist as V1 but this will take forever to search if i would want to find what callers have called a specific callee.
i have also read this HashMap with multiple values under the same key but i do not understand how to do this.
Create a bean for your value like below
class Value {
VariableType val1;
VariableType val2;
...
}
Then we can create a map like below
Map<K,Value> valueSample = new HashMap<K,Value>();
valueSample .put(new K(), new Value());
We need to set the value in Value calss by setter or constructor
One solution is to create a wrapper object (it was given in the discussion link that you have in your question) to hold values v1 and v2:
class ValueWrapper {
V1Type v1;
V2Type v2;
...
}
Now you can map your keys to the instances of this wrapper:
Map<K,ValueWrapper> sample = new HashMap<K,ValueWrapper>();
sample.put(new K(), new ValueWrapper());
If all values are <V1, V2> you can use Entry as value:
Map<K,Map.Entry<V1,V2>> sample = new HasMap<K,Map.Entry<V1,V2>>();
Create Entry<V1,V2> and put it with the relevant key.
Another solution (and even better one) is to create your own value class.
You can do like this.
Map<Integer,List<Integer>> map = new HashMap<Integer,List<Integer>>();
List<Integer> list =new ArrayList<Integer>();
list.add(55);
list.add(550);
//Adding value to the map
map.put(26, list);
//getting value from map
List<Integer> values = map.get(26);

Categories