如何将集合转换为列表?
Posted
技术标签:
【中文标题】如何将集合转换为列表?【英文标题】: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。TreeBidiMap
是OrderedMap
,顺序应该没问题。问题中要求的排序是值,而不是键。
【参考方案1】:
Java 8 以上...
您可以使用 Streams 和 Collectors.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】:您要求的操作成本很高,请确保您不需要经常执行此操作(例如在一个循环中)。
如果您需要它保持排序并且经常更新它,您可以创建一个自定义集合。例如,我想出了一个在引擎盖下有你的TreeBidiMap
和TreeMultiset
。只实施您需要的并关心数据完整性。
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 提到的是正确的,并且按原样修改 keySet
或 values
集合会使其不一致。我不知道使values
可变的任何一致方法,但是如果keySet
使用上面MyCustomCollection
类中的remove
方法,它可以支持remove
。
【讨论】:
keySet()
和 values()
是原始 Map
的视图,因此当修改它们时,支持 Map
也需要修改,您的解决方案不支持此
是的,你说得对。要做到这一点,我需要至少再创建两个集合类,以确保 keySet 和 values 都受到两个集合的支持。我更新了我的答案。【参考方案5】:
我相信你可以这样写:
coll.stream().collect(Collectors.toList())
【讨论】:
绕过投射的更好方法 太棒了!这解决了我的情况。我的 map.values() 返回一个“内部类”集合。编译器报告 Collections.sort(ListCollections.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如果 coll 已经是一个列表,我认为 Paul Tomblin 的答案可能是浪费的,因为它将创建一个新列表并复制所有元素。如果 coll 包含许多元素,这可能需要很长时间。
我的建议是:
List list;
if (coll instanceof List)
list = (List)coll;
else
list = new ArrayList(coll);
Collections.sort(list);
【讨论】:
以上是关于如何将集合转换为列表?的主要内容,如果未能解决你的问题,请参考以下文章