长列表排序列表
给定 an ArrayList<ArrayList<Long>>,我们如何根据内部列表的元素对外部列表中的元素(列表)进行排序?
约束
- 只应排序外部列表。
- 不应修改内部列表中元素的顺序。
输入:
[
[1],
[2, 5, 6],
[6, 5],
[1, 2],
[2],
[1, 2, 3],
[2, 3]
]
预期输出:
[1],
[1, 2],
[1, 2, 3],
[2],
[2, 3],
[2, 5, 6],
[6, 5]
回答
使用元素明智的比较器
比较 2 个列表
- 按索引位置的升序进行比较
- 如果找到任何非零值,则返回结果
- 否则比较列表的大小
- 使用此比较器逻辑对列表进行排序
使用每个索引比较器链。基于 WJS 的方法
- 计算所有内部列表的最大列表大小
- 为从 0 到计算出的最大大小的每个索引创建一个比较器链
- 使用此装饰(责任链)比较器对列表进行排序
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.function.IntFunction;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class SortNestedList {
protected List<List<Long>> transform(Long[][] inputArray) {
return Arrays.stream(inputArray)
.filter(Objects::nonNull) // filter outer null lists
.map(nested -> Arrays.stream(nested)
.filter(Objects::nonNull)
.collect(Collectors.toList())) // generate nested list by filtering any null values
.collect(Collectors.toList());
}
protected void sortWithElementComparator(List<List<Long>> lists) {
lists.sort((a, b) -> {
return IntStream.range(0, Math.min(a.size(), b.size())) // check till end of minimum sized list
.map(i -> Long.compare(a.get(i), b.get(i))) // compare elements at same index
.filter(i -> i != 0) // ignore equal values comparison
.findFirst() // get first non-zero comparison result (unequal)
.orElse(Integer.compare(a.size(), b.size())); // if nothing, then compare size
});
lists.forEach(System.out::println);
}
protected void sortWithDecoratedComparator(List<List<Long>> lists) {
// comparator for an index
IntFunction<Comparator<List<Long>>> elementAtIndexComparator =
index -> (a, b) -> index < Math.min(a.size(), b.size()) ?
Long.compare(a.get(index), b.get(index)) : // compare elements if index is valid for both lists
Integer.compare(a.size(), b.size()); // compare size if index is invalid for atleast 1 list
final int maxInnerIndices = lists.stream()
.mapToInt(List::size)
.max().orElse(0); // get max inner list size or 0 if empty
Comparator<List<Long>> listComparator = IntStream.range(0, maxInnerIndices)
.mapToObj(elementAtIndexComparator) // index comparator for every index
.reduce(Comparator::thenComparing) // kind of chain of responsibility / decorator
.orElse((a, b) -> 0);
lists.sort(listComparator);
lists.forEach(System.out::println);
}
protected void sort(Long[][] inputArray, int run) {
System.out.println("Sort input using direct element comparator: " + run);
sortWithElementComparator(transform(inputArray));
System.out.println("Sort input using decorated comparator: " + run);
sortWithDecoratedComparator(transform(inputArray));
}
}
测试代码
public static void main(String[] args) {
final SortNestedList sortNestedList = new SortNestedList();
int run = 0;
Long[][] inputArray = new Long[][]{};
sortNestedList.sort(inputArray, ++run);
inputArray = new Long[][]{{null}};
sortNestedList.sort(inputArray, ++run);
inputArray = new Long[][]{{null}, {1L}};
sortNestedList.sort(inputArray, ++run);
inputArray = new Long[][]{null, {1L}};
sortNestedList.sort(inputArray, ++run);
inputArray = new Long[][]{{1L}, {1L}};
sortNestedList.sort(inputArray, ++run);
inputArray = new Long[][]{{2L}, {1L}};
sortNestedList.sort(inputArray, ++run);
inputArray = new Long[][]{{2L, 1L}, {1L, 3L}};
sortNestedList.sort(inputArray, ++run);
inputArray = new Long[][]{{Long.MAX_VALUE, 1L}, {Long.MIN_VALUE, 3L}};
sortNestedList.sort(inputArray, ++run);
inputArray = new Long[][]{{1L}, {2L, 5L, 6L},
{1L, 2L}, {2L}, {1L, 2L, 3L}, {3L, 2L}, {2L, 3L},
{1L, 2L, 3L, 4L, 6L}, {1L, 2L, 3L, 4L, 5L},
{1L, 2L, 3L, 4L, 6L, 2L}, {1L, 2L, 3L, 4L, 5L, 3L, 5L},
{Long.MAX_VALUE, Long.MAX_VALUE, 1L, 5L, Long.MIN_VALUE + 1, Long.MAX_VALUE - 1},
{Long.MAX_VALUE, Long.MIN_VALUE, 1L, 5L, Long.MIN_VALUE + 1, Long.MAX_VALUE - 1},
{Long.MIN_VALUE}, {Long.MAX_VALUE}};
sortNestedList.sort(inputArray, ++run);
}
感谢 Holger 和 WJS