【问题标题】:Sort List<List<Integer>> by first number in each sub-list按每个子列表中的第一个数字对 List<List<Integer>> 进行排序
【发布时间】:2019-03-28 03:15:30
【问题描述】:

我遇到了以下问题。我有一个 ArrayList(1) 的 ArrayLists(2)。我需要做的是,对结构进行排序,使 ArrayLists(2) 的第一个元素按升序向下排列 ArrayList(1)。澄清一下:

输入:

3, 8, 6
2, 14, 205, 44, 1
1, 3

输出:

1, 3
2, 14, 205, 44, 1
3, 8, 6

看看它是如何仅根据第一个值对行进行排序的。

现在为我定义arraylists的arraylist的方式是:

List<List<Integer>> graph = new ArrayList<List<Integer>>();
// and I add elements to it likewise
graph.get(currentIndex).add(new ArrayList<Integer>());

我使用 ArrayList 的原因是因为我读到它比 LinkedList 更节省内存,并且因为我正在构建一个图的邻接列表列表。在其中,节点的数量可以变化,或者每个节点的邻接列表的长度都可以变化。一行的第一个元素是start_node,下面是它的相邻元素。你能告诉我如何实现这种排序吗?

【问题讨论】:

  • more memory efficient - 尝试阅读 LinkedList 的优势,。对于邻接列表,您应该使用LinkedList
  • 您可以将List包装在一个对象中,然后实现Comparable接口。在里面,在compareTo 你可以实现你的逻辑。此外,LinkedList 的缓存局部性更差,因此由于内存分配不连续,因此性能会更差。

标签: java list sorting arraylist data-structures


【解决方案1】:

据我了解,您希望按每个嵌套列表的第一个元素对顶级列表进行排序。它是否正确?以下是我的做法:

List<List<Integer>> graph = new ArrayList<List<Integer>>();
// add a bunch of things ...
// ...

// Now, to sort:
graph.sort((x,y) -> Integer.compare(x.get(0), y.get(0)));

这是使用Integer 来获取Comparator,这是sort() 方法需要按一些自定义标准排序的内容。在这种情况下,我们告诉它通过比较 graph 中的两个任意项目来对 ListLists graph 进行排序,方法是获取它们的第一个项目并像通常比较 Integers 一样比较它们。

请注意,这假定 graph 中的所有项目都有第一个项目。

【讨论】:

  • 顺便说一句 - 你可以更简洁(intellij 建议用 graph.sort(Comparator.comparingInt(x -&gt; x.get(0))); 替换我上面写的内容)但我喜欢上面的内容,因为它更容易理解
  • 我不明白。好像我做错了什么。我得到一个索引越界异常。排序代码实际上就是您建议的行。 Vertical length of list: 3 // it indeed is 3 java.lang.IndexOutOfBoundsException:索引:0,大小:0 在 java.util.ArrayList.rangeCheck(Unknown) at java.util.ArrayList.get(Unknown Source) at BFS.lambda$main$0(BFS.java :113)
  • 我想承认,我的代码中有一个回归。你的想法完美,非常简短和优雅。我想出了另一个解决方案,我将在帖子末尾写下来。
【解决方案2】:

要比较 2 个子列表,您需要找到第一个不相等的对,并比较它们的值(如果两者都以 32 开头,则需要查看下一个值才能看到)

List<List<Integer>> graph = new ArrayList<>();
graph.add(Arrays.asList(3, 8, 6));
graph.add(Arrays.asList(2, 14, 205, 44, 1));
graph.add(Arrays.asList(2, 14, 205, 44, 2));
graph.add(Arrays.asList(1, 3));
graph.add(Arrays.asList(1, 4));
graph.add(Arrays.asList(1, 4));
graph.add(Arrays.asList(1, 4, 5));

graph.sort((o1, o2) -> {
    int indice, cmp, min;
    for (indice = 0, min = Math.min(o1.size(), o2.size());
         indice < min; indice++) {
        if ((cmp = Integer.compare(o1.get(indice), o2.get(indice))) != 0) {
            return cmp;
        }
    }
    if (indice == o1.size()) return -1;
    if (indice == o2.size()) return 1;
    return 0;
});

System.out.println(graph);

[[1, 3], 
 [1, 4], 
 [1, 4], 
 [1, 4, 5], 
 [2, 14, 205, 44, 1], 
 [2, 14, 205, 44, 2], 
 [3, 8, 6]]

另一方面,使用Comparator 接口的另一种方式(我同意这不是很好),它比较值直到列表中的一个如果为空,然后它会比较大小如果它完全达到一个

graph.sort((o1, o2) -> {
    Comparator<List<Integer>> cc = Comparator.comparingInt(l -> l.get(0));
    int indice, min;
    for (indice = 0, min = Math.min(o1.size(), o2.size()); indice < min; indice++) {
        final int i = indice;
        cc = cc.thenComparingInt(l -> l.get(i));
    }
    return cc.thenComparingInt(List::size).compare(o1, o2);
});

【讨论】:

  • 如果 o1 等于 o2 或者如果其中一个是另一个的前缀,则会出现越界异常
  • @azro,我尝试了您的两种解决方案。最后的两个 if 意味着,如果到目前为止两个列表的所有元素都相等 - 返回更小,哪个更短?我的输入是 2 4 | 1 3 | 5 47 99,我希望前两个切换顺序。排序打印后: [] [] [2, 4, 1, 5, 5, 47, 99] 。我尝试了 ArrayLists 和 LinkedLists - 结果相同。
【解决方案3】:

所以,这是我想出的另一个解决方案。

想法是:使用 Collections 的静态方法 sort() 并将它与列表的引用和我们定义的新 Comparator 对象一起使用 compare()。

Collections.sort(graph, new Comparator<List<Integer>>(){
@Override
public int compare(List<Integer> aList1, List<Integer> aList2) {
   return aList1.get(0).compareTo(aList2.get(0));
}
}));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-07
    • 2015-01-02
    • 2011-08-05
    • 1970-01-01
    相关资源
    最近更新 更多