Getting and Printing User Inputs in HashMaps in Java - java

I stepped into Java one month ago, and have been studying then. I've come across with a problem. I need to get N number of user input pairs (key:value) to a HashMap in Java, as mentioned in below code. This gives me an InputMismatchException after entering one key:value pair. For the best of my knowledge, I can't figure out whether there is a syntax error in declared loops and assigning user input value pairs to declared HashMap. I will be really grateful if someone can elaborate this, hopefully in simple terms, as I'm a very beginner. Thank you so much for your concern.
public static void main (String [] arg){
HashMap<String, Integer> phonebook = new HashMap<>();
Scanner obj = new Scanner(System.in);
//N= Number of contacts to be entered by the user
int N = obj.nextInt();
//Getting N num of user inputs for names and contacts
while(N>0){
for (int i=0;i<N;i++)
{
//we need to input name and contact value pairs
//in same line
String name = obj.nextLine();
int contact = obj.nextInt();
//assigning user input key:value pairs to hashmap
phonebook.put(name, contact);
}
//setting key:value pairs to display
Set<String> keys = phonebook.keySet();
for(String i:keys)
{
System.out.println(i +"="+phonebook.get(i));
}
N--;
}
}

You always need to put obj.nextLine(); after you do obj.nextInt();. This is because obj.nextInt(); only consumes the number, but when you enter a number and hit the enter key, the input stream also records a newline character at the end, so the next obj.nextLine(); picks up an empty string, and you are always off by one from then on. Here's an example sequence of events:
You enter the number of inputs.
The program reads that into the variable N.
The program reads the remaining empty string into the variable name.
You enter the name.
the program tries to read a number into the variable contact, but what you entered is not a number, so it fails.
And for your own sanity, please use some indentation. Here is your corrected code, with indentation:
public static void main(String[] arg) {
HashMap<String, Integer> phonebook = new HashMap<>();
Scanner obj = new Scanner(System.in);
//N= Number of contacts to be entered by the user
int N = obj.nextInt();
obj.nextLine(); //consume the newline
//Getting N num of user inputs for names and contacts
while (N > 0) {
for (int i = 0; i < N; i++) {
//we need to input name and contact value pairs
//in same line
String name = obj.nextLine();
int contact = obj.nextInt();
obj.nextLine(); //consume the newline
//assigning user input key:value pairs to hashmap
phonebook.put(name, contact);
}
//setting key:value pairs to display
Set<String> keys = phonebook.keySet();
for (String i : keys) {
System.out.println(i + "=" + phonebook.get(i));
}
N--;
}
}
Or, if you actually want both the name and the contact to be entered on the same line as you say in the comments, you can replace this line:
String name = obj.nextLine();
With this line:
String name = obj.findInLine("\\D+");
This just tells Java to read from the input stream until it hits a digit character.

You need to add an obj.nextLine() statement after getting N. When you enter something in a prompt, there's an end-of-line character that gets added after you press enter (\n). nextInt() only reads a number, so when you call nextLine() immediately after nextInt(), it will just read the end-of-line character \n because nextInt() didn't pick it up. By adding an extra nextLine() statement after calling nextInt(), you get rid of the \n and the program can read the values properly.
This code works:
public static void main (String [] arg){
HashMap<String, Integer> phonebook = new HashMap<>();
Scanner obj = new Scanner(System.in);
//N= Number of contacts to be entered by the user
int N = obj.nextInt();
obj.nextLine();
//Getting N num of user inputs for names and contacts
while(N>0){
for (int i=0;i<N;i++)
{
//we need to input name and contact value pairs
//in same line
String name = obj.nextLine();
int contact = obj.nextInt();
obj.nextLine();
//assigning user input key:value pairs to hashmap
phonebook.put(name, contact);
}
//setting key:value pairs to display
Set<String> keys = phonebook.keySet();
for(String i:keys)
{
System.out.println(i +"="+phonebook.get(i));
}
N--;
}
}
Console input and output is below. You might want to use i < N - 1 and not i < N, because I wanted to input 2 contacts only, but had to add 3. This may confuse the user.
2
foo
100
bar
1000
bar=1000
foo=100
n
1000000
bar=1000
foo=100
n=1000000

Related

How can I obtain the first character of a string that is given by a user input in java

I want the user to input a String, lets say his or her name. The name can be Jessica or Steve. I want the program to recognize the string but only output the first three letters. It can really be any number of letters I decide I want to output (in this case 3), and yes, I have tried
charAt();
However, I do not want to hard code a string in the program, I want a user input. So it throws me an error. The code below is what I have.
public static void main(String args[]){
Scanner Name = new Scanner(System.in);
System.out.print("Insert Name here ");
System.out.print(Name.nextLine());
System.out.println();
for(int i=0; i<=2; i++){
System.out.println(Name.next(i));
}
}
the error occurs at
System.out.println(Name.next(i)); it underlines the .next area and it gives me an error that states,
"The Method next(String) in the type Scanner is not applicable for arguments (int)"
Now I know my output is supposed to be a of a string type for every iteration it should be a int, such that 0 is the first index of the string 1 should be the second and 2 should be the third index, but its a char creating a string and I get confused.
System.out.println("Enter string");
Scanner name = new Scanner(System.in);
String str= name.next();
System.out.println("Enter number of chars to be displayed");
Scanner chars = new Scanner(System.in);
int a = chars.nextInt();
System.out.println(str.substring(0, Math.min(str.length(), a)));
The char type has been essentially broken since Java 2, and legacy since Java 5. As a 16-bit value, char is physically incapable of representing most characters.
Instead, use code point integer numbers to work with individual characters.
Call String#codePoints to get an IntStream of the code point for each character.
Truncate the stream by calling limit while passing the number of characters you want.
Build a new String with resulting text by passing references to methods found on the StringBuilder class.
int limit = 3 ; // How many characters to pull from each name.
String output =
"Jessica"
.codePoints()
.limit( limit )
.collect(
StringBuilder::new,
StringBuilder::appendCodePoint,
StringBuilder::append
)
.toString()
;
Jes
When you take entry from a User it's always a good idea to validate the input to ensure it will meet the rules of your code so as not to initiate Exceptions (errors). If the entry by the User is found to be invalid then provide the opportunity for the User to enter a correct response, for example:
Scanner userInput = new Scanner(System.in);
String name = "";
// Prompt loop....
while (name.isEmpty()) {
System.out.print("Please enter Name here: --> ");
/* Get the name entry from User and trim the entry
of any possible leading or triling whitespaces. */
name = userInput.nextLine().trim();
/* Validate Entry...
If the entry is blank, just one or more whitespaces,
or is less than 3 characters in length then inform
the User of an invalid entry an to try again. */
if (name.isEmpty() || name.length() < 3) {
System.out.println("Invalid Entry (" + name + ")!\n"
+ "Name must be at least 3 characters in length!\n"
+ "Try Again...\n");
name = "";
}
}
/* If we get to this point then the entry meets our
validation rules. Now we get the first three
characters from the input name and display it. */
String shortName = name.substring(0, 3);
System.out.println();
System.out.println("Name supplied: --> " + name);
System.out.println("Short Name: --> " + shortName);
As you can see in the code above the String#substring() method is used to get the first three characters of the string (name) entered by the User.

Be able to enter a value, and a string in a java scanner to output a ranking

I'm trying to create a ranking that displays this:
int(value) - String(username)
(In total ten times even if I enter 30 values and 30 nicknames)
Here is my working code:
public class Methods {
private static final ArrayList<Double> nbAll = new ArrayList<>();
private static final ArrayList<String> pseudoAll = new ArrayList<>();
public static void test() {
try (Scanner scanner = new Scanner(System.in)) {
System.out.print(ANSI_RED + "Please enter the number of notes you want to calculate : ");
double nb = scanner.nextInt();
String pseudo = scanner.next();
for (int i = 0; i < nb; i++) {
double temp = scanner.nextDouble();
nbAll.add(temp);
}
System.out.println("------------");
System.out.println("Ranking: ");
nbAll.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);
retry();
}
}
I tried : To make a second for loop to be forced to enter the username in string but it didn't work and for the ranking I didn't succeed yet
Screen for Desired operation: https://i.imgur.com/0QlGHd8.png
In this particular case I personally think it may be a little better if you used a HashMap or Map Interface to store the required data. It's rather ideal for this sort of thing since the User Name should be unique and can be used as the Key and the Rank as the Value since several Users could potentially contain the same rank value:
Map<String, Integer> map = new HashMap<>();
Another thing which may make life a little easier is for the User to enter the Rank AND the User Name related to that rank on a single line separated with a whitespace or a tab or whatever, for example:
Ranking #1:
Enter a Rank value followed by a User Name separated with space,
for example: 250 John Doe. Enter 'd' when done.
Your entry: --> |
Of course validation would need to be carried out so to ensure proper entry is done but this isn't overly difficult using the String#matches() method and a small Regular Expression (regex), for example:
if (!myString.matches("^\\d+\\s+.{1,}$")) {
System.err.println("Invalid Entry! Try again...");
System.err.println();
myString = "";
continue;
}
What the regular expression "^\\d+\\s+.{1,}$" above passed to the String#matches() method does is that it validates the fact that the first component of the supplied User entry is in fact a string representation of a Integer value consisting of one or more digits. It then checks to make sure at least one whitespace follows that numerical value and then after the space it expects to see at least 1 (or more) of any characters after the space(s) which is to essentially be the User Name. Of course if the User enters the data incorrectly then an Invalid Entry warning would be issued and the user is given the opportunity to attempt the entry again.
Once valid input has been acquired the data now needs to of course be split into its' respective data types before it can be applied to the the Map Interface object. This of course is done with the String#split() method:
String[] stringParts = myString.split("\\s+");
This will create a String[] Array named stringParts. The \\s+ regular expression tells the split() method to split the string on one or more whitespaces ' ' (or Tabs \t, newlines \n, Carriage Returns \r, form-feeds \f, and vertical tabulations \x0B). This would cover pretty much all the cases for the Users required entry.
Now that we have the array we know that the first element of that array will be the supplied Ranking value. We want to convert this into an Integer data type before adding to our Map, like this:
int rank = Integer.parseInt(stringParts[0]);
Now we want the User Name. Because in this example we also allow for multiple names like First and Last names, a little more is involved to add the names together so to make a single User Name string from it all. Remember we split the data entry on whitespaces so if there are multiple names we could potentially have more than just two elements within the stringParts[] array. We'll need to build the userName string. We use a for loop and the StringBuilder class to do this, for example:
String[] stringParts = tmp.split("\\s+");
int rank = Integer.parseInt(stringParts [0]);
StringBuilder sb = new StringBuilder("");
for (int i = 1; i < stringParts .length; i++) {
if (!sb.toString().isEmpty()) {
sb.append(" ");
}
sb.append(stringParts [i]);
}
String userName = sb.toString();
Okay...now we have the User Name so let's make sure a ranking with that User Name isn't already contained within the Map:
if (map.containsKey(userName)) {
System.err.println("A ranking for '" + userName
+ "' has already been supplied! Try again...");
System.err.println();
myString = "";
continue;
}
If we pass to this point then all is good and we can add the data to the Map:
map.put(userName, rank);
This may seem a little long winded but in my opinion, it's not. Below is a working example or all the above in use:
Scanner userInput = new Scanner(System.in);
Map<String, Integer> map = new HashMap<>();
int count = 0;
String tmp = "";
while (tmp.isEmpty()) {
System.out.println("Ranking #" + (count+1) + ":");
System.out.print("Enter a Rank value followed by a User Name separated "
+ "with space,\nfor example: 250 John Doe. Enter 'd' when done.\n"
+ "Your entry: --> ");
tmp = userInput.nextLine();
if (tmp.equalsIgnoreCase("d")) {
break;
}
if (!tmp.matches("^\\d+\\s+.{1,}$")) {
System.err.println("Invalid Entry! Try again...");
System.err.println();
tmp = "";
continue;
}
String[] parts = tmp.split("\\s+");
int rank = Integer.parseInt(parts[0]);
StringBuilder sb = new StringBuilder("");
for (int i = 1; i < parts.length; i++) {
if (!sb.toString().isEmpty()) {
sb.append(" ");
}
sb.append(parts[i]);
}
String userName = sb.toString();
if (map.containsKey(userName)) {
System.err.println("A ranking for '" + userName
+ "' has already been supplied! Try again...");
System.err.println();
tmp = "";
continue;
}
count++;
map.put(userName, rank);
tmp = "";
System.out.println();
}
// Sort the map by RANK value in 'descending' order:
Map<String, Integer> sortedMap = map.entrySet().stream().sorted(Map.Entry.<String,
Integer>comparingByValue().reversed()).collect(java.util.stream.Collectors.toMap(Map.Entry::
getKey, Map.Entry::getValue,(e1, e2) -> e1, java.util.LinkedHashMap::new));
// If you want the Rank values sorted in 'Ascending' order then use below instead:
/* Map<String, Integer> sortedMap2= map.entrySet().stream().sorted(Map.Entry.<String,
Integer>comparingByValue()).collect(java.util.stream.Collectors.toMap(Map.Entry::
getKey, Map.Entry::getValue,(e1, e2) -> e1, java.util.LinkedHashMap::new)); */
// Display the rankings in Console Window:
System.out.println();
System.out.println("You entered " + count + " rankings and they are as follows:");
System.out.println();
// Table header
String header = String.format("%-4s %-15s %-6s",
"No.", "User Name", "Rank");
System.out.println(header);
// The header underline
System.out.println(String.join("", java.util.Collections.nCopies(header.length(), "=")));
// The rankings in spaced format...
count = 1;
for (Map.Entry<String,Integer> enties : sortedMap.entrySet()) {
System.out.printf("%-4s %-15s %-6d %n",
String.valueOf(count) + ")",
enties.getKey(),
enties.getValue());
count++;
}
When the above code is run, The User is asked to supply a Rank value and a User Name related to that rank. The User is then asked to enter another and another and another until that User enter 'd' (for done). All entries provided are then displayed within the Console Window in a table type format. The Rankings within the Map had been sorted in descending order before (highest rank first) before displaying them. If you prefer Ascending order then that code is also provided but is currently commented out.

Getting variable number of inputs Using Scanner in Java

I want to have input like:-
The first line of the input contains the two cities for where the listing of flight options must be produced – the departure city and the arrival city, separated by a white-space.
The next N lines will contain the available flights and their costs. Each line is a direct flight starting with the departure city name, followed by the arrival city name, and lastly followed by the cost of that flight – all three separate by a white-space character.
Where 1<=N<=20.
Can anyone plz help I want to know how to end the input. I am using:-
Scanner s = new Scanner(System.in);
while(!(input = s.nextLine()).equals(" "))
but all in vain.
The data is in the form of
CityA CityB // Upto its I have done. The next N lines i.e. second paragraph is a confusion
Next N lines should be in form
CityA CityC 5000
CityA CityD 3000
You can use the following code :
Scanner s = new Scanner(System.in);
int maxCount = 20;
// initialize it to a random value for now
String input = "?";
System.out.println("Enter 2 cities with cost upto 20");
while (!input.trim().equals("") && maxCount > 0) {
input = s.nextLine();
/*
* parse input accordingly
*/
maxCount--;
}
System.out.println("Done with input");
Scanner sc = new Scanner(System.in);
String input = "";
while (!(input = sc.nextLine()).equals(" ")) {
if (input.equalsIgnoreCase("EXIT")) {
break;
}
System.out.println(input);
}

How can I stop people from pressing return in my code

Hi basically wrote this code, which stores a hashmap into an external text file So when the user types in write, the first value they type after write (index 1), and the second value at index(2), gets stored as a key and value respectively. The problem is that it all has to be on one line and if the user presses return after they type in "write" the system crashes. So how can I make it so that it doesn't allow the user to press return until they have typed a key and value?
This is my code,
if (input.contains("write")) {
String key = input.get(1);
String value = "";
for(int i=2; i<input.size(); i++) {
value = value + " " + input.get(i);
}
instruct.mapWrite(key, value);
}
I use a scanner class to get input then use the following method to split the string into an Array. This is how I can store the input into a HashMap.
public ArrayList<String> getInput()
{
System.out.print("> "); // print prompt
String inputLine = reader.nextLine().trim().toLowerCase();
String[] wordArray = inputLine.split(" "); // split at spaces
// add words from array into ArrayList
ArrayList<String> words = new ArrayList<String>();
for(String word : wordArray) {
words.add(word);
}
return words;
}
You cannot prevent it at this level.
But
Instead of dumb prompt, tell the user what you expect,
check number of tokens (if(wordArray.length < 3)), print error message and ask again.

Multiple inputs with arrays

I need to write a program that helps determine a budget for "peer advising" the following year based on the current year. The user will be asked for the peer advisor names and their highest earned degree in order to determine how much to pay them. I am using a JOptionPane instead of Scanner and I'm also using an ArrayList.
Is there a way for the user to input both the name and the degree all in one input and store them as two different values, or am I going to have to have two separate input dialogs? Example: storing the name as "Name1" and the degree as "Degree1 in order to calculate their specific pay.
Also, I am using an ArrayList but I know that the list will need to hold a maximum of six (6) elements, is there a better method to do what I am trying to do?
Here is what I had down before I started thinking about this, if it's necessary.
import java.util.ArrayList;
import javax.swing.JOptionPane;
public class PeerTutoring
{
public static void main(String[] args)
{
ArrayList<String> tutors = new ArrayList<String>();
for (int i = 0; i < 6; i++)
{
String line = null;
line = JOptionPane.showInputDialog("Please enter tutor name and their highest earned degree.");
String[] result = line.split("\\s+");
String name = result[0];
String degree = result[1];
}
}
}
"Is there a way for the user to input both the name and the degree all
in one input, but store them as two different values."
Yes. You can ask the user to enter input separated with space for example, and split the result:
String[] result = line.split("\\s+"); //Split according to space(s)
String name = result[0];
String degree = result[1];
Now you have the input in two variables.
"I decided to use ArrayList but I know the number of names that will be inputed (6), is there a more appropriate array method to use?"
ArrayList is fine, but if the length is fixed, use can use a fixed size array.
Regarding OP update
You're doing it wrong, this should be like this:
ArrayList<String[]> list = new ArrayList<String[]>(6);
String[] splitted;
String line;
for(int i=0;i<6;i++) {
line = JOptionPane.showInputDialog("Please enter tutor name and their highest earned degree.");
splitted = line.split("\\s+");
list.add(splitted);
}
for(int i=0;i<6;i++)
System.out.println(Arrays.deepToString(list.get(i))); //Will print all 6 pairs
You should create an ArrayList that contains a String array that will represent the input (since the user enters pair as an input). Now, all what you have to do is to insert this pair to the ArrayList.
What you can do is store the input from you JOptionPane in a String, and then split the String into an array to store the name and degree entered. For example:
String value = null;
value = JOptionPane.showInputDialog("Please enter tutor name and
their highest earned degree.");
String[] tokens = value.split(" ");//if you input name followed by space followed by degree, this splits the input by the space between them
System.out.println(tokens[0]);//shows the name
System.out.println(tokens[1]);//shows the degree
Now you can use tokens[0] to add the name to your List.

Categories

Resources