【问题标题】:How to convert a Collection to List?如何将集合转换为列表?
【发布时间】:2010-10-09 11:20:24
【问题描述】:

我正在使用来自Apache Collections 库的TreeBidiMap。我想对 doubles 的值进行排序。

我的方法是使用以下方法检索值的Collection

Collection coll = themap.values();

这自然可以正常工作。

主要问题:我现在想知道如何将coll 转换/转换(不确定哪个正确)为List,以便对其进行排序?

然后我打算遍历已排序的 List 对象,该对象应该是有序的,并使用 themap.getKey(iterator.next())TreeBidiMap (themap) 中获取适当的键,其中迭代器将位于 @ 列表之上987654332@.

【问题讨论】:

  • 您可能希望通过直接使用某种 SortedMap 来避免此步骤,因此条目按所使用键的自然顺序排列。 Java 自己的 TreeMap 实现了 SortedMap。
  • TreeBidiMapOrderedMap,顺序应该没问题。问题中要求的排序是值,而不是键。

标签: java list sorting collections apache-commons-collection


【解决方案1】:

Java 8 以上...

您可以使用 StreamsCollectors.toCollection() 将 Collection 转换为任何集合(即 List、Set 和 Queue)。

考虑以下示例地图

Map<Integer, Double> map = Map.of(
    1, 1015.45,
    2, 8956.31,
    3, 1234.86,
    4, 2348.26,
    5, 7351.03
);

到数组列表

List<Double> arrayList = map.values()
                            .stream()
                            .collect(
                                Collectors.toCollection(ArrayList::new)
                            );

输出:[7351.03, 2348.26, 1234.86, 8956.31, 1015.45]

到 Sorted ArrayList(升序)

List<Double> arrayListSortedAsc = map.values()
                                        .stream()
                                        .sorted()
                                        .collect(
                                            Collectors.toCollection(ArrayList::new)
                                        );

输出:[1015.45, 1234.86, 2348.26, 7351.03, 8956.31]

到 Sorted ArrayList(降序)

List<Double> arrayListSortedDesc = map.values()
                                        .stream()
                                        .sorted(
                                            (a, b) -> b.compareTo(a)
                                        )
                                        .collect(
                                            Collectors.toCollection(ArrayList::new)
                                        );

输出:[8956.31、7351.03、2348.26、1234.86、1015.45]

到链表

List<Double> linkedList = map.values()
                                .stream()
                                .collect(
                                    Collectors.toCollection(LinkedList::new)
                                );

输出:[7351.03, 2348.26, 1234.86, 8956.31, 1015.45]

到哈希集

Set<Double> hashSet = map.values()
                            .stream()
                            .collect(
                                Collectors.toCollection(HashSet::new)
                            );

输出:[2348.26, 8956.31, 1015.45, 1234.86, 7351.03]

到 PriorityQueue

PriorityQueue<Double> priorityQueue = map.values()
                                            .stream()
                                            .collect(
                                                Collectors.toCollection(PriorityQueue::new)
                                            );

输出:[1015.45、1234.86、2348.26、8956.31、7351.03]

参考

Java - Package java.util.stream

Java - Package java.util

【讨论】:

    【解决方案2】:

    使用流:

    someCollection.stream().collect(Collectors.toList())
    

    【讨论】:

      【解决方案3】:

      Java 10 引入了List#copyOf,它在保留顺序的同时返回不可修改的列表

      List<Integer> list = List.copyOf(coll);
      

      【讨论】:

        【解决方案4】:

        您要求的操作成本很高,请确保您不需要经常执行此操作(例如在一个循环中)。

        如果您需要它保持排序并且经常更新它,您可以创建一个自定义集合。例如,我想出了一个在引擎盖下有你的TreeBidiMapTreeMultiset。只实施您需要的并关心数据完整性。

        class MyCustomCollection implements Map<K, V> {
            TreeBidiMap<K, V> map;
            TreeMultiset<V> multiset;
            public V put(K key, V value) {
                removeValue(map.put(key, value));
                multiset.add(value);
            }
            public boolean remove(K key) {
                removeValue(map.remove(key));
            }
            /** removes value that was removed/replaced in map */
            private removeValue(V value) {
                if (value != null) {
                    multiset.remove(value);
                }
            }
            public Set<K> keySet() {
                return Collections.unmodifiableSet(map.keySet());
            }
            public Collection<V> values() {
                return Collections.unmodifiableCollection(multiset);
            }
            // many more methods to be implemented, e.g. count, isEmpty etc.
            // but these are fairly simple
        }
        

        这样,您就有一个从values() 返回的排序 Multiset。但是,如果您需要它是一个列表(例如,您需要类似数组的 get(index) 方法),则需要更复杂的东西。

        为简洁起见,我只返回不可修改的集合。 @Lino 提到的是正确的,并且按原样修改 keySetvalues 集合会使其不一致。我不知道使values 可变的任何一致方法,但是如果keySet 使用上面MyCustomCollection 类中的remove 方法,它可以支持remove

        【讨论】:

        • keySet()values() 是原始 Map 的视图,因此当修改它们时,支持 Map 也需要修改,您的解决方案不支持此
        • 是的,你说得对。要做到这一点,我需要至少再创建两个集合类,以确保 keySet 和 values 都受到两个集合的支持。我更新了我的答案。
        【解决方案5】:

        我相信你可以这样写:

        coll.stream().collect(Collectors.toList())
        

        【讨论】:

        • 绕过投射的更好方法
        • 太棒了!这解决了我的情况。我的 map.values() 返回一个“内部类”集合。编译器报告 Collections.sort(List ) 不接受 Collections.sort(List)。
        • 不适用于我在 android 中的用例。需要最低 api 24
        【解决方案6】:
        Collections.sort( new ArrayList( coll ) );
        

        【讨论】:

        • 缺少访问 ArrayList 的引用?
        • @Zach:嗯嗯嗯好点。我知道我有理由将其标记为 CW。顺便说一句,保罗的答案就是一个。我不知道为什么他只有我的紫外线。
        【解决方案7】:

        这样的事情应该可以工作,调用带有集合的ArrayList constructor

        List theList = new ArrayList(coll);
        

        【讨论】:

          【解决方案8】:

          这是一个次优的单线解决方案:

          Collections.list(Collections.enumeration(coll));
          

          【讨论】:

            【解决方案9】:

            @Kunigami:我想你可能对 Guava 的newArrayList 方法有误解。它不检查 Iterable 是否为 List 类型,而只是按原样返回给定的 List。它总是创建一个新列表:

            @GwtCompatible(serializable = true)
            public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements) {
              checkNotNull(elements); // for GWT
              // Let ArrayList's sizing logic work, if possible
              return (elements instanceof Collection)
                  ? new ArrayList<E>(Collections2.cast(elements))
                  : newArrayList(elements.iterator());
            }
            

            【讨论】:

            • 这不是更多的投票吗? Kunigami 的回答是不正确的(就其对底层实现的假设而言)。
            【解决方案10】:
            List list = new ArrayList(coll);
            Collections.sort(list);
            

            正如 Erel Segal Halevi 下面所说,如果 coll 已经是一个列表,您可以跳过第一步。但这将取决于 TreeBidiMap 的内部结构。

            List list;
            if (coll instanceof List)
              list = (List)coll;
            else
              list = new ArrayList(coll);
            

            【讨论】:

            • 请注意,这两种方法有不同的副作用:将集合转换为列表然后排序也会对原始集合进行排序;不会创建副本。
            • 如果重复使用,这种方法会大大降低性能。请参阅我的答案以获取即时有效的解决方案,它涉及自定义集合。
            • 这并不能解决 map.values() 返回“内部类”集合的情况。编译器报告 Collections.sort(List ) 不接受 Collections.sort(List)。解决方案甚至是使用: List list = map.values().stream().collect(Collectors.toList())
            【解决方案11】:

            如果 coll 已经是一个列表,我认为 Paul Tomblin 的答案可能是浪费的,因为它将创建一个新列表并复制所有元素。如果 coll 包含许多元素,这可能需要很长时间。

            我的建议是:

            List list;
            if (coll instanceof List)
              list = (List)coll;
            else
              list = new ArrayList(coll);
            Collections.sort(list);
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-01-29
              • 1970-01-01
              • 2013-12-16
              • 1970-01-01
              • 2017-02-06
              • 1970-01-01
              • 2011-09-29
              • 1970-01-01
              相关资源
              最近更新 更多