Java 在流上使用 Collections.toMap() 时如何保持 List 的迭代顺序?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29090277/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I keep the iteration order of a List when using Collections.toMap() on a stream?
提问by Ashika Umanga Umagiliya
I am creating a Map
from a List
as follows:
我正在Map
从 a创建一个List
如下:
List<String> strings = Arrays.asList("a", "bb", "ccc");
Map<String, Integer> map = strings.stream()
.collect(Collectors.toMap(Function.identity(), String::length));
I want to keep the same iteration order as was in the List
. How can I create a LinkedHashMap
using the Collectors.toMap()
methods?
我想保持与List
. 如何LinkedHashMap
使用这些Collectors.toMap()
方法创建一个?
采纳答案by prunge
The 2-parameter version of Collectors.toMap()
uses a HashMap
:
的2 参数版本Collectors.toMap()
使用一个HashMap
:
public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(
Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper)
{
return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
}
To use the 4-parameter version, you can replace:
要使用4 参数版本,您可以替换:
Collectors.toMap(Function.identity(), String::length)
with:
和:
Collectors.toMap(
Function.identity(),
String::length,
(u, v) -> {
throw new IllegalStateException(String.format("Duplicate key %s", u));
},
LinkedHashMap::new
)
Or to make it a bit cleaner, write a new toLinkedMap()
method and use that:
或者为了让它更简洁,编写一个新toLinkedMap()
方法并使用它:
public class MoreCollectors
{
public static <T, K, U> Collector<T, ?, Map<K,U>> toLinkedMap(
Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper)
{
return Collectors.toMap(
keyMapper,
valueMapper,
(u, v) -> {
throw new IllegalStateException(String.format("Duplicate key %s", u));
},
LinkedHashMap::new
);
}
}
回答by hzitoun
Provide your own Supplier
, Accumulator
and Combiner
:
提供您自己的Supplier
,Accumulator
和Combiner
:
List<String> myList = Arrays.asList("a", "bb", "ccc");
// or since java 9 List.of("a", "bb", "ccc");
LinkedHashMap<String, Integer> mapInOrder = myList
.stream()
.collect(
LinkedHashMap::new, // Supplier
(map, item) -> map.put(item, item.length()), // Accumulator
Map::putAll); // Combiner
System.out.println(mapInOrder); // {a=1, bb=2, ccc=3}
回答by Mateen Ulhaq
In Kotlin, toMap()
is order-preserving.
在 Kotlin 中,toMap()
是保序的。
fun <K, V> Iterable<Pair<K, V>>.toMap(): Map<K, V>
Returns a new map containing all key-value pairs from the given collection of pairs.
The returned map preserves the entry iteration order of the original collection. If any of two pairs would have the same key the last one gets added to the map.
fun <K, V> Iterable<Pair<K, V>>.toMap(): Map<K, V>
返回包含给定对集合中所有键值对的新映射。
返回的映射保留原始集合的条目迭代顺序。如果两对中的任何一对具有相同的键,则最后一对被添加到映射中。
Here's its implementation:
这是它的实现:
public fun <K, V> Iterable<Pair<K, V>>.toMap(): Map<K, V> {
if (this is Collection) {
return when (size) {
0 -> emptyMap()
1 -> mapOf(if (this is List) this[0] else iterator().next())
else -> toMap(LinkedHashMap<K, V>(mapCapacity(size)))
}
}
return toMap(LinkedHashMap<K, V>()).optimizeReadOnlyMap()
}
The usage is simply:
用法很简单:
val strings = listOf("a", "bb", "ccc")
val map = strings.map { it to it.length }.toMap()
The underlying collection for map
is a LinkedHashMap
(which is insertion-ordered).
for 的基础集合map
是 a LinkedHashMap
(按插入顺序排列)。