I am trying to compare elements in Array. for example,
labels = ["abc1","abc2","abc3","abc4"]
I want to take the String with the highest values. In this case its abc4. I'm pretty new to coding so if anyone could help me with the logic, it would be great.
What you are looking for is a method that compares each string to each other.
Java has a built-in method way to do this for the String class, called the compareTo method. As it's name suggests, it compares one string to another.
String a = "abc1";
String b = "abc2";
String c = "abc1";
System.out.println(a.compareTo(b)); // prints a negative number because `a` is smaller than `b`
System.out.println(b.compareTo(a)); // prints a positive number because `b` is bigger than `a`
System.out.println(c.compareTo(a)); // prints 0 because `a` and `b` have the same letters.
See the official java doc for the compareTo method:
[Returns]the value 0 if the argument string is equal to this string; a value less than 0 if this string is lexicographically less than the string argument; and a value greater than 0 if this string is lexicographically greater than the string argument.
The way you could use this in your example would be:
String biggest = labels[0];
for(int i = 1; i < labels.length; i++){
if(biggest.compareTo(labels[i]) < 0) biggest = labels[i];
}
System.out.println(biggest);
Note: For more details on how this method chooses which one is "bigger", see the java doc (linked above). If you have your own rules about which one should be bigger, then you can make your own method to define that.
UPDATE:
For example, see XtremeBaumer's comment
"abc20".compareTo("abc100") = 1. Indicating that abc20 is bigger than abc100, thus making compareTo() not necessarily useful for the task
Your question need improvement, based on what you said, lets remove all the abc from the Strings ,get the max integer and then return or print "abc" concatenated to the max number :
import java.util.Arrays;
import java.util.stream.IntStream;
public class Solution {
public static void main(String[] args) throws Throwable {
int numberOfElements = 100;
String[] labels = new String[numberOfElements];
Arrays.setAll(labels, element -> "abc" + element);
int max = Arrays.stream(labels).mapToInt(element -> Integer.parseInt(element.substring(3))).max().getAsInt();
System.out.println(String.join(" | ", labels));
System.out.println();
System.out.println();
System.out.println("The max here is : ");
System.out.println("abc" + max);
}
}
Output here :
abc0 | | abc1 | | abc2 | | abc3 | | abc4 ...... || abc99
The max here is :
abc99
Try something like this:
var strings = new ArrayList<String>();
strings.add("abc1");
strings.add("abc2");
strings.add("abc3");
strings.add("abc4");
var integers = strings
.stream()
.map(string -> Integer.valueOf(string.replaceAll("[^0-9]+", "")))
.collect(Collectors.toList());
var max = Collections.max(integers);
var indexMax = integers.indexOf(max);
var maxString = strings.get(indexMax);
System.out.println(maxString);
Simpler way : #mcieciel has already posted this one.
List<String> list = Arrays.asList("abc1", "abc22", "abc33", "abc19");
List<Integer> intList = list.stream()
.map(s -> Integer.parseInt(s.replaceAll("[^0-9]+", "")))
.collect(Collectors.toList());
int index = intList.indexOf(Collections.max(intList));
System.out.println(list.get(index));
Another way is creating a map which will have string and its corresponding integer value in key-value pairs.Then find the max value with its key from the map.
This might be an overkill .
String key = list.stream()
.collect(Collectors.toMap( // creating map like this format : abc1->1 , abc22->22 ...
Function.identity(), // key of the map i.e the string value
s -> Integer.parseInt(s.replaceAll("[^0-9]+", "")), // integer value
(e1, e2) -> e1)) // if multiple same entry exists choose one
.entrySet() // now we have map, we can iterate and find out the key which holds max value
.stream()
.max((e1, e2) -> Integer.compare(e1.getValue(), e2.getValue())) // comparing values
.get()
.getKey();
System.out.println(key);
Note : if you have string values without any digit,both will not work.
Related
I've got:
String s = "ZpglnRxqenU"
I need to assign a number to each character in the string like:
z-1
p-2
g-3
l-4
n-5
r-6
x-7
q-8
e-9
n-10
u-11
I do not want to count the frequency of characters.
I tried to use HashMap:
Map<String, Integer> map = new HashMap<>();
for (int i = 0; i < s.length(); i++) {
map.put(String.valueOf(s.charAt(i)), i + 1);
}
But Map a has unique key and I lost first n occurrence
How do I count letters?
If you want to count the number of characters in a string use s.length();.
If you want to count the number of different characters in a String, you already can with the code you wrote. map.size() will give exactly that, because the map only stores each key once (in your case the 'letters' (they are called char's in java, chars is a diminutive for characters)).
How put() in maps work:
The first time you put a key to the map, it is added with the value you give, the second time the value is changed.
Swap the key-value of your map. Use the number for the key, as it will be unique.
Use a NavigableMap to keep them in order.
NavigableMap< Integer , String > = new TreeMap<>() ;
Example code using conventional style.
String input = "ZpglnRxqenU";
int[] codePoints = input.codePoints().toArray();
NavigableMap < Integer, String > numberedCharacters = new TreeMap <>();
for ( int ordinal = 1 ; ordinal <= codePoints.length ; ordinal++ )
{
numberedCharacters.putIfAbsent(
ordinal ,
Character.toString( codePoints[ ordinal - 1 ] )
);
}
Example code using streams & lambdas. Same effect, not necessarily better in this particular case.
String input = "ZpglnRxqenU";
int[] codePoints = input.codePoints().toArray();
NavigableMap < Integer, String > numberedCharacters =
IntStream
.rangeClosed( 1 , codePoints.length )
.boxed()
.collect(
Collectors.toMap(
Function.identity() ,
ordinal -> Character.toString( codePoints[ ordinal - 1 ] ) ,
( o1 , o2 ) -> o1 ,
TreeMap :: new )
);
To get all the characters from the map, call values. The resulting Collection object promises to iterate in the order of iteration of the map’s keys.
String recreated = String.join( "" , numberedCharacters.values() );
Dump to console.
System.out.println( "input = " + input );
System.out.println( "numberedCharacters = " + numberedCharacters );
System.out.println( "recreated = " + recreated );
When run.
input = ZpglnRxqenU
numberedCharacters = {1=Z, 2=p, 3=g, 4=l, 5=n, 6=R, 7=x, 8=q, 9=e, 10=n, 11=U}
recreated = ZpglnRxqenU
Basil's solution should be good enough for what you want but if you strictly want to model like in your example you can have a List<Pair<Character, Integer>> as a storage for your data. There are many libraries offering Pair or Tuplestructures or you could just create your own.
Populating your list is a matter of personal taste but in essence you iterate over the characters array, map each character and its index to a new Pair(char, idx) then collect them in a list
I want to create a method that converts a string-value into a double after a specific string.
For example:
String text1 = "--generalus! -maximus? --petrus 23 --param 123.456";
I am searching for the value after the word param has appeared. If there is no param-word, I have to return a Double.NaN.
I tried to split the String into an array to work with the index but the parseDouble-method isn't working...
Can you maybe help me?
public double parseParam(String text) {
String[] arr = text.split("\\s");
String param = "param";
for (int i = 0; i < arr.length;i++){
System.out.println(arr[i]); //just for me to show whats going on
if(arr[i].equals(param)){
return Double.parseDouble(arr[i+1]);
}
}
return Double.NaN;
}
You could use a regular expression. Find --param followed by one or more whitespace and then a floating point value. Group that value. And then parse it (if it is found). Like,
String text1 = "--generalus! -maximus? --petrus 23 --param 123.456";
Pattern p = Pattern.compile("--param\\s+([+-]?\\d*([.]?\\d+))");
Matcher m = p.matcher(text1);
double val = Double.NaN;
if (m.find()) {
val = Double.parseDouble(m.group(1));
}
System.out.println(val);
Outputs
123.456
It will work if you compare "--param" instead of "param".
It may be needed to parse all the parameters in the input string which resemble command-line options using a 3rd-party library such as Apache Commons CLI, or a map of key-value pairs may be built and relevant parameter could be be retrieved from the map by the parameter name:
String text1 = "--generalus! -maximus? --petrus 23 --param 123.456";
Map<String, String> map = Arrays.stream(text1.split("[\\-]+")) // Stream<String>
.filter(s -> s != null && !s.trim().isEmpty()) // remove blanks
.map(pair -> pair.split("\\s+")) // Stream<String[]> pairs
.collect(Collectors.toMap(
p -> p[0],
p -> p.length > 1 ? p[1] : ""
));
System.out.println(map);
// available parameter
System.out.println(Double.parseDouble(map.getOrDefault("param", "NaN")));
// missing parameter
System.out.println(Double.parseDouble(map.getOrDefault("param1", "NaN")));
Output:
{maximus?=, petrus=23, param=123.456, generalus!=}
123.456
NaN
How do we get next key/value pair of a linkedhashmap using an enhanced for loop in Java?
What we want to achieve is to get a value from a linkedhashmap and pair it with the next value in the linkedhashmap. To achieve this, first of all, we have a list looking like the following:
LinkedHashMap<String, String> dates = new LinkedHashMap<String, String>();
// first quarter
dates.put("January", "2021-01-01");
dates.put("March", "2021-03-31");
// second quarter
dates.put("April", "2021-04-01");
dates.put("June", "2021-06-30");
// third quarter
dates.put("July", "2021-07-01");
dates.put("September", "2021-09-30");
// fourth quarter
dates.put("Oktober", "2021-10-01");
dates.put("December", "2021-12-31");
Above outputs:
{January=2021-01-01, March=2021-03-31, April=2021-04-01, June=2021-06-30, July=2021-07-01, September=2021-09-30, Oktober=2021-10-01, December=2021-12-31}
Then we want to select 2021-01-01 and then pair it with 2021-03-31. We then want 2021-04-01 and pair it with its next value, which is 2021-06-30 and so on... To achieve this, we have a function, where we initialize a enhanced for loop to get the values of the linkedhashmap. We use modulo to only select every second date starting from the first date, but we are only able to retrieve the first value, but not the second. Then using modulo, we select the third, but not the fourth value.
public void modtagMomsAngivelse() {
String serviceResponse = "";
int count = 0;
for (String name: dates.keySet()) {
if((count%2) == 0) {
String startDate = dates.get(name).toString();
// ----> String endDate = dates.next().get(name).toString(); <---- NEED SOMETHING LIKE THIS, BUT IS IT POSSIBLE?
system.out.println(startDate + " | " + endDate)
}
count++;
}
}
Above should output the following:
2021-01-01 | 2021-03-31
2021-04-01 | 2021-06-30
2021-07-01 | 2021-09-30
2021-10-01 | 2021-12-31
How can it be programmed correctly in Java?
You can't do this with an enhanced for loop. You have to use an Iterator directly:
Iterator<String> it = dates.keySet().iterator();
while (it.hasNext()) {
String startDateKey = it.next();
String endDateKey = it.next(); // Will fail if there isn't another element.
String startDate = dates.get(startDateKey).toString();
String endDate = dates.get(endDateKey).toString();
// ...
}
If dates isn't large, it may be easier to copy into a List, and then access by index:
List<String> keys = new ArrayList<>(dates.keySet());
for (int k = 0; k < keys.size(); k += 2) {
String startDateKey = keys.get(k);
String endDateKey = keys.get(k + 1); // Will fail if there isn't another element. Can change condition to `k + 1 < keys.size()`, if you want to miss off an unpaired element.
// ...
}
Really, a (LinkedHash)Map isn't an ideal structure to be holding together pairs of keys with semantic meaning. It would be better to store those keys together, as a single key object.
I have a HashMap made of two types: String as Keys, which are Player names and Integer as values, which are scores.
I am creating a ranking system, and for that, I need to get the two highest values from this HashMap, so the top two players that were put into it.
For example:
If these were the values of my HashMap:
Key Value
String1 1
String2 2
String3 3
String4 4
String5 5
I would want a way to only return String4 and String5.
I thought that getting the entrySet would be enough, but there's no get method in a Set, so I can't get value 0 (highest) and value 1 (second highest).
I also tried using
Collections.max(map);
And it wouldn't accept a HashMap as an argument
And
final String[] top = new String[1];
int topInt = 0;
map.forEach((s, i) -> {if (i > topInt) top[0] = s;});
But that didn't quite work either, it was way too slow for my performance.
How do I obtain both highest values?
Try something like this. I haven't tested it, let me know if I overlooked something.
int highest = Integer.MIN_VALUE;
String highestString = null;
int secondHighest = Integer.MIN_VALUE;
String secondHighestString = null;
for(Map.Entry<String, Integer> pair : yourHashMap.entrySet())
{
if(highest < pair.getValue())
{
secondHighest = highest;
secondHighestString = highestString;
highest = pair.getValue();
highestString = pair.getKey();
}
}
Also as others have stated in the comments; this is probably not the best approach, as you could have multiple values of the same value with different keys. If indexing is what you are after use an array, ArrayList, or something from the java.util.Collections class.
I have a LinkedHashMapcalled generateMapwhich contains a string as a key and all possible variations of the following character of this string stored as value(s).
Now I'd like to print a random text. (The storage of the String is not the issue)
Example:
String = "Lorem ipsum Loram ipar"
Key----------Value
After Lor -> e,a
After ore -> m
After rem -> " "
After em -> i
After m i -> p,p
After ip -> s,a
The random text should be generated with randomly chosen next character, then the next "window" is chosen, and so on. I have no idea how to generate a new text, maybe you can give me a hint?
This is what I got so far:
for (Entry<String, ArrayList<String>> e : generateMap.entrySet()) {
//store the values into an ArrayList
ArrayList<String> valuesList = new ArrayList<String>(e.getValue());
// randomly choose on of the values
int random = (int) (Math.random() * (valuesList.size()));
String randomWort = valuesList.get(random);
String print = e.getKey() + randomWort;
}
System.out.println(print);
I think your code is ok. In convenient way, to use Guava class LinkedHashMultimap.
A small improvement: you do not need create an ArrayList in the loop, e.getValue() is ArrayList already.