简体   繁体   中英

Sort List<List<Integer>> in Java

I am trying to sort a List<List<Integer>> lexicographical manner. But I'm unable to achieve the goal and don't get where is the issue.

List<List<Integer>> result = new ArrayList<List<Integer>>();

    result.add(Arrays.asList(1, 3, 76, 99));
    result.add(Arrays.asList(1, 2, 84, 92));
    result.add(Arrays.asList(1, 1, 76, 99));

    java.util.Collections.sort(result, (item1, item2) -> {

        if (item1.get(0) > item2.get(0) || item1.get(1) > item2.get(1) || item1.get(2) > item2.get(2)
                || item1.get(3) > item2.get(3)) {
            return 1;
        } else {
            return -1;
        }
    });

Expected output: [[1, 1, 76, 99], [1, 2, 84, 92], [1, 3, 76, 99]]

But I'm getting [[1, 3, 76, 99], [1, 2, 84, 92], [1, 1, 76, 99]]

I want that index wise smallest number will come first. In the example, all three lists have 1 at the first position, so no change. At the second position, 3rd list has 1 which is the minimum among the three so 3rd list will be moved to the first. Then considering the 2nd item of 2nd and 3rd list 2 is lower so second list will remain at the 2nd position.

The condition you have is wrong. When item1.get(0) < item2.get(0) you simply continue your short-circuited comparison instead of returning -1. Also, any time you have a comparator that does not return 0, I get automatically suspicious.

A simple fix would be to use a loop:

for(int i = 0; i < 4; i++) {
    int i1 = item1.get(i);
    int i2 = item2.get(i);
    if(i1 < i2) {
        return -1;
    } else if(i1 > i2) {
        return 1;
    }
}
return 0;

You could simplify the loop to

for(int i = 0; i < 4; i++) {
    int d = item1.get(i) - item2.get(i);
    if(d != 0) {
        return d;
    }
}
return 0;

You can do it in a generic way, based on MatinS answer :

class ListComparator<T extends Comparable<T>> implements Comparator<List<T>> {

  @Override
  public int compare(List<T> o1, List<T> o2) {
    for (int i = 0; i < Math.min(o1.size(), o2.size()); i++) {
      int c = o1.get(i).compareTo(o2.get(i));
      if (c != 0) {
        return c;
      }
    }
    return Integer.compare(o1.size(), o2.size());
  }

}

Then sorting is easy

List<List<Integer>> listOfLists = ...;

Collections.sort(listOfLists, new ListComparator<>());

Building off of Mad Physicist's answer, here is a more general solution and usage:

public final class SortingListOfListExample {

  public static void main(final String[] args) {
    final List<List<Integer>> result = new ArrayList<>();

    result.add(List.of(1, 3, 76, 99));
    result.add(List.of(1, 2, 84, 92));
    result.add(List.of(1, 1, 76, 99));

    System.out.println(result);

    result.sort(new ListComparator<>());

    System.out.println(result);
  }

  private static final class ListComparator<T extends Comparable<T>> implements Comparator<List<T>> {

    @Override
    public final int compare(final List<T> list1, final List<T> list2) {
      final int minSize = Math.min(list1.size(), list2.size());

      for(int i = 0; i < minSize; i++) {
        // Be wary of nulls.
        final int compareResult = list1.get(i).compareTo(list2.get(i));

        if(compareResult != 0) {
          return compareResult;
        }
      }

      return Integer.compare(list1.size(), list2.size());
    }

  }

}

If you are using Java 9 or higher, you could stream over the indices of the shortest list and drop while all elemts at corsponding indices are equal to find the first index which holds elments that differ. If such an index is present compare the elemnts at that index, if not compare the list size:

import java.util.Comparator;
import java.util.OptionalInt;
import java.util.stream.IntStream;

....


public static void main(String[] args){
    List<List<Integer>> result = new ArrayList<>();
    result.add(Arrays.asList(1, 3, 76, 99));
    result.add(Arrays.asList(1, 2, 84, 92));
    result.add(Arrays.asList(1, 1, 76, 99));

    Comparator<List<Integer>> comparator =  (a,b) -> {
        OptionalInt comp = IntStream.range(0, Math.min(a.size(),b.size()))
                                    .dropWhile(i -> a.get(i).equals(b.get(i)))
                                    .findFirst();
        return comp.isPresent() ?
                Integer.compare(a.get(comp.getAsInt()), b.get(comp.getAsInt())) :
                Integer.compare(a.size(), b.size());
    };

    result.sort(comparator);

    System.out.println(result);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM