[英]Sort a list of lists using comparator
我正在尋找使用比較器整理列表列表(在ArrayLists上)。 訂單最大的地方。 所有子列表將始終具有相同的大小。
例如,列表
[[4,5,6], [7,9,10], [4,7,8], [1,2,3], [7,9,12]]
這應該
[[7,9,12], [7,9,10], [4,7,8], [4,5,6], [1,2,3]]
我有這樣的東西,但只按每個列表中的第一項排序
List<List<Integer>> list = Arrays.asList(
Arrays.asList(4,5,6),
Arrays.asList(7,9,10),
Arrays.asList(4,7,8),
Arrays.asList(1,2,3),
Arrays.asList(7,9,12));
list.sort((l1, l2) -> l2.get(0).compareTo(l1.get(0)));
哪個產生:
[[7, 9, 10], [7, 9, 12], [4, 5, 6], [4, 7, 8], [1, 2, 3]]
如何編寫一個比較器,如果前面的項目相等,它將按列表中的下一項進行排序?
例如,[7,9,10],[7,9,12]應該比較兩個7,然后是兩個9然后是10和12.例如,[4,5,6],[4, 7,8]應該比較兩個4,然后4和7然后停止。
您可以這樣定義比較器:
Comparator<List<Integer>> comparator = (list1, list2) -> {
for (int i = 0; i < list1.size(); i++) {
int value = Integer.compare(list2.get(i), list1.get(i));
if (value != 0)
return value;
}
return 0;
};
要么:
Comparator<List<Integer>> comparator = (list1, list2) ->
IntStream.range(0, list1.size())
.map(i -> Integer.compare(list2.get(i), list1.get(i)))
.filter(value -> value != 0)
.findFirst()
.orElse(0);
然后排序:
list.sort(comparator);
更新 :
您可以通過創建返回比較器的自定義泛型函數來進一步概括:
static <T extends Comparable<T>> Comparator<List<T>> comparator(){
return (o1, o2) -> IntStream.range(0, o1.size())
.map(i -> o2.get(i).compareTo(o1.get(i)))
.filter(value -> value != 0)
.findFirst()
.orElse(0);
}
現在你可以這樣做:
List<List<Integer>> integerList = Arrays.asList(
Arrays.asList(4,5,6),
Arrays.asList(7,9,10),
Arrays.asList(4,7,8),
Arrays.asList(1,2,3),
Arrays.asList(7,9,12));
integerList.sort(comparator()); // sort list of integers descending
List<List<String>> stringList = Arrays.asList(
Arrays.asList("a","b","c"),
Arrays.asList("d","e","f"),
Arrays.asList("g","h","i"));
stringList.sort(comparator()); // sort list of strings descending
等等......
注 - 我使用的是JDK 9+,所以我不知道在JDK 8 之前的版本中類型推斷是否足夠好。
由於您希望按降序對整數進行排序,因此首先要創建一個比較器來執行該操作,然后將其鏈接在一起多次以創建列表的比較器:
Comparator<Integer> intReversed = Integer::compare;
intReversed = intReversed.reversed(); // integer reversed order comparator
// Chain comparators for 3 indices (could also do this in a loop for lists of unknown size)
// Each step compares the extracted element using the given comparator:
Comparator<List<Integer>> comp = Comparator.comparing(l -> l.get(0), intReversed);
comp = comp.thenComparing(l -> l.get(1), intReversed);
comp = comp.thenComparing(l -> l.get(2), intReversed);
list.sort(comp);
System.out.println(list); // [[7, 9, 12], [7, 9, 10], [4, 7, 8], [4, 5, 6], [1, 2, 3]]
您嘗試實現的排序順序稱為Lexicographical order 。
為了比較具有此順序的兩個列表,您可以簡單地遍歷列表,並比較相應的元素。 只要一個比較產生非零值,就可以返回該值。 如果所有元素都相等,則返回零。
因此,您可以使用通用方法實現此比較的核心:
private static <T> int compareLexicographically(
List<? extends T> list0,
List<? extends T> list1,
Comparator<? super T> comparator)
基於此方法,您可以組裝不同類型的比較器。 對於Integer
值(以及實現Comparable
接口的其他類型),可以使用Comparator#naturalOrder
比較器作為最后一個參數。 對於其他類型,您可以使用不同的比較器。 例如,您也可以選擇創建反向比較器 。
下面是一個示例,說明如何實現此類方法並將其用於排序Integer
對象, String
對象或自定義對象(此處為簡單的Person
類,通過其getName
進行比較)。
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class LexicographicalComparator
{
public static void main(String[] args)
{
exampleWithIntegers();
exampleWithStrings();
exampleWithPersons();
}
private static void exampleWithIntegers()
{
List<List<Integer>> list = Arrays.asList(
Arrays.asList(4, 5, 6),
Arrays.asList(7, 9, 10),
Arrays.asList(4, 7, 8),
Arrays.asList(1, 2, 3),
Arrays.asList(7, 9, 12));
Comparator<List<Integer>> comparator = lexicographicalComparator();
list.sort(comparator.reversed());
System.out.println("Integers, descending:");
list.forEach(System.out::println);
}
private static void exampleWithStrings()
{
List<List<String>> list = Arrays.asList(
Arrays.asList("B", "B", "C"),
Arrays.asList("C", "B", "B"),
Arrays.asList("B", "C", "A"),
Arrays.asList("A", "C", "B"),
Arrays.asList("C", "B", "A"));
Comparator<List<String>> comparator = lexicographicalComparator();
list.sort(comparator);
System.out.println("Strings, ascending:");
list.forEach(System.out::println);
}
private static void exampleWithPersons()
{
class Person
{
String name;
Person(String name)
{
this.name = name;
}
String getName()
{
return name;
}
@Override
public java.lang.String toString()
{
return name;
}
}
List<List<Person>> list = Arrays.asList(
Arrays.asList(new Person("B"), new Person("B"), new Person("C")),
Arrays.asList(new Person("C"), new Person("B"), new Person("B")),
Arrays.asList(new Person("B"), new Person("C"), new Person("A")),
Arrays.asList(new Person("A"), new Person("C"), new Person("B")),
Arrays.asList(new Person("C"), new Person("B"), new Person("A")));
Comparator<List<Person>> comparator =
lexicographicalComparator(Comparator.comparing(Person::getName));
list.sort(comparator);
System.out.println("Persons, by name, ascending:");
list.forEach(System.out::println);
}
private static <T extends Comparable<? super T>> Comparator<List<T>>
lexicographicalComparator()
{
return (list0, list1) ->
compareLexicographically(list0, list1, Comparator.naturalOrder());
}
private static <T> Comparator<List<T>> lexicographicalComparator(
Comparator<? super T> comparator)
{
return (list0, list1) ->
compareLexicographically(list0, list1, comparator);
}
private static <T> int compareLexicographically(
List<? extends T> list0,
List<? extends T> list1,
Comparator<? super T> comparator)
{
if (list0.size() < list1.size())
{
return -1;
}
if (list0.size() > list1.size())
{
return 1;
}
for (int i = 0; i < list0.size(); i++)
{
T t0 = list0.get(i);
T t1 = list1.get(i);
int value = comparator.compare(t0, t1);
if (value != 0)
{
return value;
}
}
return 0;
}
}
你可能仍然需要考慮角落案件。 最重要的是:
null
元素時會發生什么? 第一個目前通過基本上按照大小排序列表來處理,這可能是也可能不是你想要的。
后者可以通過將Comparator#nullsFirst
或Comparator#nullsLast
比較器傳遞給外部方法來輕松處理,但您必須知道這一點。
實際上你根據Lists
的第一個元素排序:
list.sort((l1, l2) -> l2.get(0).compareTo(l1.get(0)));
要么比較所有元素,要注意如果你的List沒有相同的長度,你也必須處理它。
或者將List
的元素轉換為String
然后比較這個String:
list.sort((l1, l2) -> l2.toString()
.compareTo(l1.toString()));
這種方式的優點是即使使用不同大小的String
List
可以工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.