1

I have e.g list of elemenets like sg-1, sg-5, sg-13, sg-6 and etc and i need sort them by numbers. The part of my code is:

}).map(c -> { System.out.println(c); return c; }).distinct() .sorted((c1, c2) -> c1.substring(c1.indexOf("-"), c1.length()) .compareTo(c2.substring(c2.indexOf("-"), c2.length()))) .collect(Collectors.toList()); 

system out prints sg-1 sg-1 sg-1 sg-9 sg-1 sg-4 sg-15 sg-1 sg-1 sg-1 sg-1

But in the end I get [sg-1, sg-15, sg-4, sg-9] however it has to be [sg-1, sg-4, sg-9, sg-15] How to sort them, please help my :)

2
  • c1.substring(c1.indexOf("-"), c1.length()) return a value with the dash(-) which is considered as a negative number. For example, your code will return -1, -5 , -13 instead of 1,5,13, You could use c1.substring(c1.indexOf("-") + 1, c1.length()) to skip the dash (-). I dont understand why you are using map. Commented Apr 12, 2018 at 19:08
  • So, yeah, you are right, However I have tried to use .sorted((c1, c2) -> c1.substring(c1.indexOf("-") + 1, c1.length()) .compareTo(c2.substring(c2.indexOf("-") + 1, c2.length()))) .collect(Collectors.toList()); But it doesen't work. May be "comparedTo" cannot correctly sort the numbers, if they are string not int or integer ? Commented Apr 12, 2018 at 19:41

2 Answers 2

4

The first thing you're doing wrong is that you're comparing strings lexicographically and not integers as you might be expecting.

Second, even if you were to convert c1.substring(c1.indexOf("-"), c1.length()) to integer and then compare you'll still get incorrect results.

why is that?

This is because c1.substring(c1.indexOf("-"), c1.length()), the first argument to substring is inclusive , this means you'll always extract negative numbers.

Solution:

  1. You'll actually need to compare integers as opposed to strings.
  2. The first argument to substring should actually be c1.indexOf("-") + 1 to start after the "-".

List<String> result = list.stream() .distinct() .sorted(Comparator.comparingInt(s -> Integer.parseInt(s.substring(s.indexOf("-") + 1, s.length())))) .collect(Collectors.toList()); 

As an aside, don't use map to perform debugging work, instead utilise peek.

List<String> result = list.stream() .peek(System.out::println) .distinct() .sorted(Comparator.comparingInt(s -> Integer.parseInt(s.substring(s.indexOf("-") + 1, s.length())))) .collect(Collectors.toList()); 
Sign up to request clarification or add additional context in comments.

2 Comments

Note that there is a single-argument version of substring which already implies length() as second parameter. Further, if you can preclude leading zeros, you can stay with string comparison when you just prepend a length comparison: Comparator.comparingInt((String s) -> s.length()-s.indexOf("-")) .thenComparing(s -> s.substring(s.indexOf("-")+1))
@Holger good shout! completely forgot about that overload at the time of writing and thanks to the following suggestion as well. appreciated as always.
1

Please try this out

List<String> result = list.stream().distinct().sorted((a1,a2)->{ return Integer.compare(Integer.parseInt(a1.split("-")[1]), Integer.parseInt(a2.split("-")[1])); }).collect(Collectors.toList()); 

4 Comments

It works, but could you explain me, what do these [1] mean ? and why with my code I do not get the sorted result?
The piece of code splits the individual strings considering the dash(-). It then takes the second part of the string that is the numbers at the end. For "sg-1" is split it into "sg" and "1". It takes the number and converts to an integer and compares it. Hope this helps.
avoid using raw types. it's much better to utilise generics.
Also, your current approach is inefficient as it creates two array objects for each time the function to sorted is invoked and this can be avoided.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.