我正在寻找使用比较器整理列表列表(在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并停止。
答案 0 :(得分:3)
您可以这样定义比较器:
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版本中的类型推断是否足够好。
答案 1 :(得分:1)
由于您希望按降序对整数进行排序,因此首先要创建一个比较器来执行该操作,然后将其链接在一起多次以创建列表的比较器:
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]]
答案 2 :(得分:1)
您尝试实现的排序顺序称为Lexicographical order。
为了比较具有此顺序的两个列表,您可以简单地浏览列表,并比较相应的元素。只要一个比较产生非零值,就可以返回该值。如果所有元素都相等,则返回零。
因此,您可以使用通用方法实现此比较的核心:
private static <T> int compareLexicographically(
List<? extends T> list0,
List<? extends T> list1,
Comparator<? super T> comparator)
基于此方法,您可以组装不同类型的比较器。对于Integer
值(以及实现Comparable
接口的其他类型),可以使用Comparator#naturalOrder
比较器作为最后一个参数。对于其他类型,您可以使用不同的比较器。您也可以选择从中创建reversed comparator,例如。
这是一个示例,说明如何实现这样的方法并用于排序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
个元素时会发生什么? 第一个目前通过基本上按照 size 对列表进行排序来处理,这可能是您想要的,也可能不是。
后者可以通过将Comparator#nullsFirst
或Comparator#nullsLast
比较器传递给外部方法来轻松处理,但您必须注意这一点。
答案 3 :(得分:0)
实际上,您根据Lists
的第一个元素进行排序:
list.sort((l1, l2) -> l2.get(0).compareTo(l1.get(0)));
要么比较所有元素,要注意如果你的List没有相同的长度,你也必须处理它。
或者将List
的元素转换为String
,然后比较此字符串:
list.sort((l1, l2) -> l2.toString()
.compareTo(l1.toString()));
即使List
String
大小不同,这种方式也有效。