2

I have List of Double Array and I would like sort it according to first and last field. So far I am able to sort it by only 1 element of array.

Real state:

0         1         2
-------  -------  -------
78       100        0
78       100        1
0        100        0
104      100        1

Expected:

0         1         2
-------  -------  -------
0        100       0
78       100       1
78       100       0
101      100       1

I want to sort field according to value of 1st element of Array. If value of 1st and 2nd are equal I want to sort according to 3rd element where first should be 1 and then 0 (there will be only 1 and 0 value)

List<Double[]> splitList = new ArrayList<>();
Double[] tmp1 = { 78d, 100d, 0d };
Double[] tmp2 = { 78d, 100d, 1d };
Double[] tmp3 = { 0d, 100d, 0d };
Double[] tmp4 = { 104d, 100d, 1d };
splitList.add(tmp1);
splitList.add(tmp2);
splitList.add(tmp3);
splitList.add(tmp4);
splitList.sort(Comparator.comparingDouble(a -> a[0]));

This one sort me according to first element. I found solution to sort by two elements https://stackoverflow.com/a/26865122/9774735 so I tried it:

splitList.sort(Comparator.comparingDouble(a -> a[0]).thenComparingDouble(b -> b[2]));

and it output me an error:

Multiple markers at this line
    - The type of the expression must be an array type but it resolved 
     to Object
    - The type of the expression must be an array type but it resolved 

How can I compare List of Array?

Bob
  • 309
  • 2
  • 5
  • 17

3 Answers3

5

Seems like the java compiler has problems in infering the generic type, you have some options to overcome this problem:

  1. Use type hints with the pattern Class.<GenericType>.method(Arguments):

    splitList.sort(Comparator.<Double[]>comparingDouble(a -> a[0]).thenComparingDouble(b -> b[2]));
    
  2. Declare the lambda parameter type (declaring it for the first seems to be enough):

    splitList.sort(Comparator.comparingDouble((Double[] a) -> a[0]).thenComparingDouble(b -> b[2]));
    

After reading your comments you want to reverse the last comparison, which can be done like this:

Comparator.<Double[]>comparingDouble(a -> a[0])
   .thenComparing(Comparator.<Double[]>comparingDouble(b -> b[2]).reversed())

Which is quite messy, you're better of using something like this:

splitList.sort((a, b) -> {
    int c = Double.compare(a[0], b[0]);
    return c == 0 ? Double.compare(b[2], a[2]) : c;
});
Lino
  • 19,604
  • 6
  • 47
  • 65
  • I suppose that the 0 would be before 1 (Im talking about 3rd element). I want 1 to be first and then 0. – Bob Feb 04 '19 at 14:08
2

Try this:

    splitList.sort((a,b) -> {
        int r = a[0].compareTo(b[0]);
        if (r == 0) {
            r = a[2].compareTo(b[2]);
        }
        return r;
    });
Maurice Perry
  • 9,261
  • 2
  • 12
  • 24
1

If you use java 8 or next version you can use this:

splitList.stream()
            .sorted(Comparator.comparing((Double[] array) -> array[0])
                    .thenComparing(Comparator.comparing((Double[] array2) -> array2[2]).reversed()));

to print in console:

splitList.stream()
            .sorted(Comparator.comparing((Double[] array) -> array[0])
                    .thenComparing(Comparator.comparing((Double[] array2) -> array2[2]).reversed()))
            .forEach(array -> System.out.println(Arrays.toString(array)));

or you can collect in a list then can print the list too:

List<Double[]> list = splitList.stream()
            .sorted(Comparator.comparing((Double[] array) -> array[0])
                    .thenComparing(Comparator.comparing((Double[] array2) -> array2[2]).reversed()))
            .collect(Collectors.toList());

for (Double[] array: list) {
    System.out.println(Arrays.toString(array));
}

Best of luck!

Mukit09
  • 2,956
  • 3
  • 24
  • 44