I was wondering if there's a way to get an index, let me show you an example.
String[] names = {"Daniel", "Lewis", "Sarah", "John"};
String cmd = input.nextLine();
String CMD[] = cmd.split(" ");
if (CMD[0].equalsIgnoreCase("my name is") && CMD[1].equalsIgnoreCase(accountIndex[0])){
System.out.println("My name is Daniel!");
} else if (CMD[0].equalsIgnoreCase("my name is") && CMD[1].equalsIgnoreCase(accountIndex[1])) {
System.out.println("My name is Lewis!");
} else if (CMD[0].equalsIgnoreCase("my name is") && CMD[1].equalsIgnoreCase(accountIndex[2])) {
System.out.println("My name is Sarah!");
} else if (CMD[0].equalsIgnoreCase("my name is") && CMD[1].equalsIgnoreCase(accountIndex[3])) {
System.out.println("My name is John!");
}
Is there an easier way to do this, than nesting if statements?
Please note, I'd only want to use names inside of the table, so I can't just make a String called myName equal to CMD[1].
I suppose it's sort of like a database of usernames, if your username doesn't exist, you can't log in.
I want it like that, but without nesting loads of if statements, and the names Array would be the database in this instance.
You could do
List<String> names = Arrays.asList("Daniel", "Lewis", "Sarah", "John");
if (names.contains(CMD[3]) {
System.out.println("My name is " + CMD[0]);
} else {
// not found...
}
You are splitting on a space, so
CMD[0].equalsIgnoreCase("my name is")
will never evaluate to true.
Why are you testing for "my name is " at all? Just capture the fourth word, if that is the format you're using: CMD[3].
To avoid these if-else-if-elses, put the names into a Map where the key is the name, and the value is always null.
Then test the name against the keys:
if(mapOfNames.containsKey(CMD[3]))
You can try a for loop:
for (int i = 0; i < names.length(); i++) {
if (CMD[3].equalsIgnoreCase(accountIndex[i])) {
System.out.println("My name is " + names[i] + "!");
break;
}
}
Running cmd.split() will split the array giving you an array: {"my", "name", "is", "some_name"}. Which means that the name you want to check will be given at the fourth element in the array hence index [3].
String[] names = {"Daniel", "Lewis", "Sarah", "John"};
String cmd = input.nextLine();
String CMD[] = cmd.split(" ");
// Initial check to see if my name is exists.
if(cmd.subtstring(0, 10).equalsIgnoreCase("my name is") && cmd.length > 3)
{
// This loop is better than checking each individual case because it allows you to dynamically add elements to your names array
for(int i = 0; i < names.length; i++)
{
// Must start at the fourth element since my, name, and is will be the 0-2 elements.
if(CMD[3].equalsIgnoreCase(names[i]))
{
System.out.println("My name is "+names[i]+"!");
break;
}
}
}
You can store the valid usernames in a TreesSet and then when user enters a name you can lookup the TreeSet to test if the given name is a valid name.
TreeSet<String> validNames = new TreeSet<String>();
validNames.add("John");
validNames.add("Mary");
.....
.....
// For searching
if(validNames.contains(CMD[0]))
{
// name exists
}
else{
// invalid name
}
Note : You can store the names in any searchable collection (HashMaps are also a good choice for this scenario. This is just a pointer and you need to deep dig to find which Data structure suits your need. For more information you can refer the following links :
TreeSet
HashMap
You can convert array to list and then search for the name in the list with contains method:
if(Arrays.asList(names).contains(CMD[3]))
System.out.println("My name is " + CMD[3] + "!");
Related
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.
I have a string where i need to place the values from the list,But when i for loop the list i will get one value at a iteration.
public class Test2 {
public static void main(String[] args) throws ParseException, JSONException {
List<String> value=new ArrayList<String>();
value.add("RAM");
value.add("26");
value.add("INDIA");
for(int i=0;i<value.size();i++){
String template="My name is "+value.get(i) +" age is "+value.get(i)+" country is"+value.get(i);
System.out.println(value.get(i));
}
o/p should be like this: String ="My name is +"+RAM +"age is "+26+"Country is"+INDIA;
}
}
You don't need a for loop, simply access the elements using index of the List as shown below:
System.out.println("My name is "+value.get(0) +
" age is "+value.get(1)+" country is"+value.get(2));
Also, I suggest you use StringBuilder for appending strings which is a best practice, as shown below:
StringBuilder output = new StringBuilder();
output.append("My name is ").append(value.get(0)).append(" age is ").
append(value.get(1)).append(" country is ").append(value.get(2));
System.out.println(output.toString());
What's happening is that in each iteration you're taking the i-th element of the list and you're placing it in all the positions of your String template.
As #javaguy says, there's no need to use a for loop if you only have those three items in your list, and another solution is to use String.format:
String template = "My name is %s age is %s country is %s";
String output = String.format(template, value.get(0), value.get(1), value.get(2));
It's probably a bit slower (interesting discussion here) but performances don't seem to be relevant in your case, so the choiche between the two options would be mostly based on personal taste.
You do not need any loop! Also you do not need any array list I am sorry but I could fully understand what exactly you need but I this code will help you:
List<String> value = new ArrayList<String>();
value.add("RAM");
value.add("26");
value.add("INDIA");
String template = "My name is " + value.get(0) + " age is " + value.get(1) + " country is" + value.get(2);
System.out.println(template);
// o/p should be like this: String ="My name is +"+RAM +"age is
// "+26+"Country is"+INDIA;
I have a program that requests the first and last names of 10 people from the console and then adds them to a Linked List under a single entity, 'fullName'. Is there a way to use Collections.sort() to sort the names based on the last name and not the first. The order of first name then last name needs to be kept. This is what I have so far:
public void requestNames(){
for(int i = 1; i < 11; i++){
// Request first name.
System.out.print("Enter first name of friend # " + i + ":");
String fName = scanner.nextLine();
// Request last name.
System.out.print("Enter last name of friend # " + i + ":");
String lName = scanner.nextLine();
// Concatenate first and last name and hold in fullName variable.
String fullName = fName + " " + lName;
myList.add(fullName);
}
scanner.close();
}
public void sortList(){
Collections.sort(myList);
}
Yes. Provided that you are using LinkedList from the Java Collections API, you can write a custom comparator for this operation.
Collections.sort(myList, new Comparator<String, String>() {
public int compare(String left, String right) {
String leftLast = String.split("\\s")[1];
String rightLast = String.split("\\s")[1];
return leftLast.compareTo(rightLast);
}
}
Graphically, create a LinkedList “Full name” of your first name and last name combined. Perform the
following operations on the LinkedList.
Split Full name into two lists, “First name” and “last name” containing your first and last
name.
Empty “last name”
Copy “First name” to “last name”.
I am creating a program that lets you store 10 items in an array. What I haven't been able to get the program to do is give an error if one of the entered items already exists in the array.
So, for example, if the array looks like [banana, potato, 3, 4, yes, ...] and I enter banana again, it should say "Item has already been stored" and ask me to re-enter the value. The code I currently have is:
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
int stringNumber = 0;
String[] stringArray = new String[10];
for (int i = 0; i <= stringArray.length; i++) {
out.println("\nEnter a string");
String input = keyboard.next();
stringArray[stringNumber] = input;
out.println("\"" + stringArray[stringNumber] + "\"" + " has been stored.");
PrintArray(stringArray);
stringNumber++;
You can use nested loops to go through the array to see if the new input exists. It would be better to do this in a function. Also when doing this you need to make sure that you are not at the first element or you will get a null pointer exception.
for (int i = 0; i <= stringArray.length; i++) {
boolean isInArray = false;
System.out.println("\nEnter a string");
String input = keyboard.next();
if (i > 0) {
for (int j = 0; j < stringArray.length; j++) {
if (stringArray[j].equalsIgnoreCase(input)) {
isInArray = true;
break;
}
}
}
if (!isInArray) {
stringArray[stringNumber] = input;
} else {
System.out.println("\"" + stringArray[stringNumber-1] + "\""
+ " has been stored.");
}
PrintArray(stringArray);
stringNumber++;
}
It's always better to use a HashSet when you don't want to store duplicates. Then use HashSet#contains() method to check if element is already there. If ordering is important, then use LinkedHashSet.
If you really want to use an array, you can write a utility method contains() for an array. Pass the array, and the value to search for.
public static boolean contains(String[] array, String value) {
// Iterate over the array using for loop
// For each string, check if it equals to value.
// Return true, if it is equal, else continue iteration
// After the iteration ends, directly return false.
}
For iterating over the array, check enhanced for statement.
For comparing String, use String#equals(Object) method.
When you got the String input, you can create a method that will :
Go through the entire array and check if the string is in it (you can use equals() to check content of Strings)
Returns a boolean value wheter the string is in the array or not
Then just add a while structure to re-ask for an input
Basically it can look like this :
String input = "";
do {
input = keyboard.next();
}while(!checkString(input))
The checkString method will just go through all the array(using a for loop as you did to add elements) and returns the appropriate boolean value.
Without introducing some order in your array and without using an addition structure for instance HashSet, you will have to look through the whole array and compare the new item to each of the items already present in the array.
For me the best solution is to have a helper HashSet to check the item for presence.
Also have a look at this question.
To avoid you should use an Set instead of an array and loop until size = 10.
If you need to keep an array, you can use the .contains() method to check if the item is already present in the array.
while (no input or duplicated){
ask for a new string
if (not duplicated) {
store the string in the array
break;
}
}
You should check the input value in array before inserting into it. You can write a method like exists which accepts String[] & String as input parameter, and find the string into the String array, if it finds the result then return true else false.
public boolean exists(String[] strs, String search){
for(String str : strs){
if(str.equals(search))
return true;
}
return false;
}
performance would be O(n) as it searchs linearly.
I have created a table and some buttons to remove/add rows.
Problem is, when I add a new row, I must insert a value in the field name which isn't already on that table. Let me explain.
Here is the default table:
Now imagine i remove Station 3:
If i add a new Station, I would want to add a new Station name Station 3 (which is missing on the list) but I am adding a new Station 5 (obviously as my code is not correct).
My code for the Add Button action event is as such:
private void jButton10ActionPerformed(java.awt.event.ActionEvent evt) {
DefaultTableModel model = (DefaultTableModel)jTable1.getModel();
String s2 = "";
String s1 = "Station 1 Station 2 Station 3 Station 4 Station 5";
int tb1rows = jTable1.getRowCount();
if (tb1rows == 5) {
// ERROR - MAXIMUM STATION NUMBER
}
else {
for (int i=0; i<tb1rows;i++) {
s2.concat(jTable1.getValueAt(i,1).toString());
s2.concat(" ");
}
String[] s3=s2.split(" ");
for (int i=0;i<s3.length;i++) {
if (s1.contains(s3[i])) {
System.err.println("contains");
System.out.println(s3[i]);
}
}
model.insertRow(jTable1.getRowCount(),new Object[] {jTable1.getRowCount() + 1,"Station " + (jTable1.getRowCount()+1),10,false,0,Color.BLACK});
}
}
What's wrong with my logic? Is there a better way to handle the problem so that I can get the "Station x" that is missing in that column so that I can re-add it?
Thanks in advance for your answers.
As there is a space in "Station 1" split on space won't do. Instead using another separator like ";", better use a Set<String> values = new HashSet<String>().
So long as you have
"Station " + (jTable1.getRowCount()+1)
the new station is always going to be named "Station N + 1".
Assuming you fix the problem of splitting on a space described by another answer, your code should be something like
for (int i=0;i<s3.length;i++) {
if (s1.contains(s3[i])) {
System.err.println("contains");
System.out.println(s3[i]);
}
else {
model.insertRow(jTable1.getRowCount(),new Object[] {jTable1.getRowCount() + 1,"Station " + (i + 1) ,10,false,0,Color.BLACK});
}
}
instead of all that string manipulation, you could use set mainpulations:
HashSet<String> all = new HashSet<String>();
// then populate all with your 5 station strings (loop)
HashSet<String> have = new HashSet<String>();
// then populate all with the contents of your table (loop)
all.removeAll(have);
// all now contains the ones that weren't in the table.
if its ordered you can just find the first gap and insert there. so iterate over the rows and if nextrow.numberInIt > thisrow+1 you insert thisrow+1
Code should be something like this:
int nextNrToInsert;
for(int=0; i < tb1rows; i++){
thisrowNr = jTable1.getValueAt(i,1).toString();
NextrowNr = jTable1.getValueAt(i+1,1).toString();
if(nextrowNr > thisrowNr+1){
//found the gap
nextNrToInsert = thisrowNr+1;
break;
}
}
//change this to use nextNrToInsert
model.insertRow(jTable1.getRowCount(),new Object[] {jTable1.getRowCount() + 1,"Station " + (jTable1.getRowCount()+1),10,false,0,Color.BLACK});
This line is the issue
model.insertRow(jTable1.getRowCount(),new Object[] {jTable1.getRowCount() + 1,"Station " + (jTable1.getRowCount()+1),10,false,0,Color.BLACK});
You're always adding in the row with the rowCount() + 1. So even if you remove Station 3, there are 4 rows, and you're adding in row + 1.
This code has no effect:
for (int i=0; i<tb1rows;i++) {
s2.concat(jTable1.getValueAt(i,1).toString());
s2.concat(" ");
}
At loop exit, s2 will still be an empty string, so s3 will be an empty array.
But, the approach to concatenate strings and then split them is misguided, anyway. If all you need is find the lowest integer that, appended to "Station" will produce a unique string, the most natural approach is to make your own TableModel that uses a list of your own objects for each row's data. In that data you'll keep the integer itself, and not the entire string "Station n". Then it's going to be a trivial matter to find a hole in the list of integers.