I implemented two Hashtable as shown below.
HashMap<Integer,String> streetno=new HashMap<Integer,String>();
streetno.put(1, "Sachin Tendulkar");
streetno.put(2, "Dravid");
streetno.put(3,"Sehwag");
streetno.put(4,"Laxman");
streetno.put(5,"Kohli");
HashMap<String,Integer> streetname=new HashMap<String,Integer>();
streetname.put("Sachin Tendulkar",1);
streetname.put("Dravid",2);
streetname.put("Sehwag",3);
streetname.put("Laxman",4);
streetname.put("Kohli",5);
Iterator itr=streetno.keySet().iterator();
Now I'm asking user for input. If he enters the integer I want to retrieve particular value from the 1st hash table and if user enter the string I want to read the particular integer from 2nd hashtable.
My question is "How can I read the input from the user??" Because I don't know whether user enters the integer or string??
And I also wanted to know Can I retrieve particular value using Iterator depending on the key??
How can I read the input from the user??
Something like
String line = scanner.nextLine();
Because I don't know whether user enters the integer or string??
Try to convert it to an integer
try {
int num = Integer.parseInt(line);
// lookup by number
} catch(NumberFormatException ignored) {
// lookup by string
}
Can I retrieve particular value using Iterator depending on the key??
An Iterator is for iterating, a Map is for looking up by key.
First, you'll need to read the standard input. Handle it first as a String, to simplify.
Scanner scanner=new Scanner(System.in);
String userInput=scanner.nextLine();
Then, try to convert the String to an Integer. If the user typed a number, you'll get the key a the first Map, otherwise, you can asume it's a String key for the second one:
String sName;
Integer iNumber;
try {
iNumber=Integer.parseInt(userInput);
//user intruduced a number, so get the streename
sName=streetno.get(iNumber);
} catch (NumberFormatException e) {
//user introduced a not-numeric String, so get the streetnumber
sName=userInput;
iNumber=streetname.get(sName);
}
You don't need to iterate over the keyset, as the Map.get() method will return you the corresponding value.
finally, don't forget to release the scanner (better in a finally block):
scanner.close();
You can read the input as mentioned in other answers. I just tried the main logic in this way. If combining two maps can be done, you can try this way.
String input = "Laxman";
HashMap<String, String> street = new HashMap<String, String>();
street.put("1", "Sachin Tendulkar");
street.put("2", "Dravid");
street.put("3", "Sehwag");
street.put("4", "Laxman");
for (Map.Entry<String, String> entry : street.entrySet()) {
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
if (input.equals(entry.getKey())) {
System.out.println(entry.getValue());
break;
} else if (input.equals(entry.getValue())) {
System.out.println(entry.getKey());
break;
}
}
I believe you'll need to use Integer.parseInt to figure out whether the input is and integer or not.
Unfortunately, there isn't really a "tryParse" or something like that in java, so you'll have to just catch the exception. You could use a regex to check whether it is numeric or not, but this might be more hassle than it is worth.
As far as reading in from the console, I would use:
Scanner console = new Scanner( System.in );
Read the input as a string; if it can be parsed as an Integer, use streetno, otherwise use streetname.
You can use the Scanner class to retrieve user input. It has several useful methods like nextInt() or nextLine() which can be used to your advantage to determine if a user has entered an int or a string.
You can also make the user "say" what they are entering beforehand - int or string. But this is not very user friendly.
To get a value from a HashMap use the get(key) method, when providing the key.
Related
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.
I have a HashMap. I wrote a method for reading files and printing them, but I just thought that HashMap does not tolerate duplicate keys in the file, so I need to do something about it, e.g. saving the same key but with some kind of a character in the end (like just _ or something like that so they differ from each other). I can't come up with the solution (maybe I could catch an exception of just write an if-block). Could you please help me?
public static HashMap<String, String> hashmapReader(File test3) {
HashMap<String, String> data = new HashMap<>();
try (BufferedReader hmReader = new BufferedReader(new FileReader(test3))) {
String line;
while ((line = hmReader.readLine()) != null) {
String[] columns = line.split("\t");
String key = columns[0];
String value = columns[1];
data.put(key, value);
}
} catch (Exception e) {
System.out.println("Something went wrong");
}
return data;
}
You can add a control on the key if it already exist in the HashMap data.
In order to do this you can use get(key) method of the HashMap Java Class which returns null if the key doesn't exist:
if(data.get(key) != null)
key = key + "_";
data.put(key, value); //adding the split line array to the ArrayList
If it already exists (didn't return null) then you can change his name by adding a character at the end, e.g. "_" as you said.
EDIT: The answer above mine pointed out to me a fact: "What if there are more than 2 identical keys?".
For this reason, I recommend following his solution instead of mine.
To achieve what you actually ask for:
Before your put line:
while (data.containsKey(key)) key += "_";
data.put(key, value);
This will keep on checking the map to see if key already exists, and if it does, it adds the _ to the end, and tries again.
You can do these two lines in one:
while (data.putIfAbsent(key, value) != null) key += "_";
This does basically the same, but it just avoids having to look up twice in the case that the key isn't found (and thus the value should be inserted).
However, consider whether this is actually the best thing to do: how will you then look up things by "key", if you've essentially made up the keys while reading them.
You can keep multiple values per key by using a value type which stores multiple values, e.g. List<String>.
HashMap<String, List<String>> data = new HashMap<>();
// ...
data.computeIfAbsent(key, k -> new ArrayList<>()).add(value);
I'm checking to see if a key in my HashMap exists, if it does, I also want to check to see if any other keys have a value with the same name as that of the original key I checked for or not.
For example I have this.
System.out.println("What course do you want to search?");
String searchcourse = input.nextLine();
boolean coursefound = false;
if(hashmap.containsKey(searchcourse) == true){
coursefound = true;
}
This checks to see if the key exists in my hashmap, but now I need to check every single key's values for a specific value, in this case the string searchcourse.
Usually I would use a basic for loop to iterate through something like this, but it doesn't work with HashMaps. My values are also stored in a String ArrayList, if that helps.
You will want to look at each entry in the HashMap. This loop should check the contents of the ArrayList for your searchcourse and print out the key that contained the value.
for (Map.Entry<String,ArrayList> entries : hashmap.entrySet()) {
if (entries.getValue().contains(searchcourse)) {
System.out.println(entries.getKey() + " contains " + searchcourse);
}
}
Here are the relevant javadocs:
Map.Entry
HashMap entrySet method
ArrayList contains method
You can have a bi-directional map. E.g. you can have a Map<Value, Set<Key>> or MultiMap for the values to keys or you can use a bi-directional map which is planned to be added to Guava.
As I understand your question, the values in your Map are List<String>. That is, your Map is declares as Map<String, List<String>>. If so:
for (List<String> listOfStrings : myMap.values()) [
if (listOfStrings .contains(searchcourse) {
// do something
}
}
If the values are just Strings, i.e. the Map is a Map<String, String>, then #Matt has the simple answer.
I created a HashMap to store a text file with the columns of information. I compared the key to a specific name and stored the values of the HashMap into an ArrayList. When I try to println my ArrayList, it only outputs the last value and leaves out all the other values that match that key.
This isn't my entire code just my two loops that read in the text file, stores into the HashMap and then into the ArrayList. I know it has something to do with my loops.
Did some editing and got it to output, but all my values are displayed multiple times.
My output looks like this.
North America:
[ Anguilla, Anguilla, Antigua and Barbuda, Antigua and Barbuda, Antigua and Barbuda, Aruba, Aruba, Aruba,
HashMap<String, String> both = new HashMap<String, String>();
ArrayList<String> sort = new ArrayList<String>();
//ArrayList<String> sort2 = new ArrayList<String>();
// We need a try catch block so we can handle any potential IO errors
try {
try {
inputStream = new BufferedReader(new FileReader(filePath));
String lineContent = null;
// Loop will iterate over each line within the file.
// It will stop when no new lines are found.
while ((lineContent = inputStream.readLine()) != null) {
String column[]= lineContent.split(",");
both.put(column[0], column[1]);
Set set = both.entrySet();
//Get an iterator
Iterator i = set.iterator();
// Display elements
while(i.hasNext()) {
Map.Entry me = (Map.Entry)i.next();
if(me.getKey().equals("North America"))
{
String value= (String) me.getValue();
sort.add(value);
}
}
}
System.out.println("North America:");
System.out.println(sort);
System.out.println("\n");
}
Map keys need to be unique. Your code is working according to spec.
if you need to have many values for a key, you may use
Map<key,List<T>>
here T is String (not only list you can use any collection)
Some things seems wrong with your code :
you are iterating on the Map EntrySet to get just one value (you could just use the following code :
if (both.containsKey("North America"))
sort.add(both.get("North America"));
it seems that you can have "North America" more than one time in your input file, but you are storing it in a Map, so each time you store a new value for "North America" in your Map, it will overwrite the current value
I don't know what the type of sort is, but what is printed by System.out.print(sort); is dependent of the toString() implementation of this type, and the fact that you use print() instead of println() may also create problems depending on how you run your program (some shells may not print the last value for instance).
If you want more help, you may want to provide us with the following things :
sample of the input file
declaration of sort
sample of output
what you want to obtain.
I was wondering if its possible to store an object into a arraylist where the user wants it. For my program its storing the users data into a cell of their choice via an "account number" but every time I type in a new account number it says that the array isn't big enough basically. Here is my code. If anyone could help that would be appreciated.
ArrayList <Account> account = new ArrayList<Account>();
int accountNumber;
String nCity;
String nState;
String nZipCode;
String nLastName;
String nAddress;
String firstName;
String nAccount;
public void newAccount()
{
Account a = new Account();
a.firstName = JOptionPane.showInputDialog("What's your first name?");
a.nLastName = JOptionPane.showInputDialog("What's your last name?");
a.nAddress = JOptionPane.showInputDialog("What's your current address?");
a.nCity= JOptionPane.showInputDialog("What's your current city?");
a.nState = JOptionPane.showInputDialog("What's your current State?");
a.nZipCode = JOptionPane.showInputDialog("What's your current Zip Code?");
String num = JOptionPane.showInputDialog("What do you want your account number to be?");
accountNumber = Integer.parseInt(num);
account.add(accountNumber, a);
Use a HashMap and use the account number as the key
Map<Integer,Account> account =new Hashmap<Integer,Account>();
account.put(accountNumber,a);
You have created an ArrayList<Account> and you are adding elements into it in the form of key-value pair.
If you want to add that way, you probably need a HashMap: -
Map<Integer, Account> accounts = new HashMap<Integer, Account>();
then, to add entry in it, you can use Map#put() method: -
accounts.put(accountNumber, a);
Agree with the above suggestions about using Map.
Your "array isn't big enough" is simply because you are trying to specify the index of the List while you haven't initialize the indexes yet.
Simply, you are using this method of List:
add(int index, E element)
Inserts the specified element at the specified position in this list.
The keyword is INSERT.
So, imagine if your "accountNumber" is 100, and you don't have the 99 elements before it, trying to insert will make no sense in logic because you are inserting into nowhere.
JavaSE6 API says under this method:
IndexOutOfBoundsException - if the index is out of range (index < 0 || index > size())
By the way, another solution, if available to you, besides using Map is to have accountNumber as another field of Account, and you can use List now with the single-argument add() method.