与流映射的 Java 8 列表
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32859038/
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
Java 8 list to map with stream
提问by Nikolay
I have a List<Item>
collection.
I need to convert it into Map<Integer, Item>
The key of the map must be the index of the item in the collection.
I can not figure it out how to do this with streams.
Something like:
我有一个List<Item>
收藏。我需要将其转换Map<Integer, Item>
为地图的键必须是集合中项目的索引。我无法弄清楚如何使用流来做到这一点。就像是:
items.stream().collect(Collectors.toMap(...));
Any help?
有什么帮助吗?
As this question is identified as possible duplicate I need to add that my concrete problem was - how to get the position of the item in the list and put it as a key value
由于此问题被确定为可能重复,因此我需要补充一点,我的具体问题是 - 如何获取项目在列表中的位置并将其作为键值
回答by Eran
You can create a Stream
of the indices using an IntStream
and then convert them to a Map
:
您可以使用 a 创建Stream
索引IntStream
,然后将它们转换为 a Map
:
Map<Integer,Item> map =
IntStream.range(0,items.size())
.boxed()
.collect(Collectors.toMap (i -> i, i -> items.get(i)));
回答by akhil_mittal
This is updated answer and has none of the problems mentioned in comments.
这是更新的答案,没有评论中提到的任何问题。
Map<Integer,Item> outputMap = IntStream.range(0,inputList.size()).boxed().collect(Collectors.toMap(Function.identity(), i->inputList.get(i)));
回答by Pepijn Schmitz
Don't feel like you have to do everythingin/with the stream. I would just do:
不要觉得您必须在流中/与流一起做所有事情。我只会做:
AtomicInteger index = new AtomicInteger();
items.stream().collect(Collectors.toMap(i -> index.getAndIncrement(), i -> i));
As long as you don't parallelise the stream this will work and it avoids potentially expensive and/or problematic (in the case of duplicates) get()
and indexOf()
operations.
只要您不并行化流,这就会起作用,并且可以避免潜在的昂贵和/或有问题(在重复的情况下)get()
和indexOf()
操作。
(You cannot use a regular int
variable in place of the AtomicInteger
because variables used from outside a lambda expression must be effectively final. Note that when uncontested (as in this case), AtomicInteger
is very fast and won't pose a performance problem. But if it worries you you can use a non-thread-safe counter.)
(您不能使用常规int
变量代替 ,AtomicInteger
因为从 lambda 表达式外部使用的变量必须是有效的最终变量。请注意,当无争议时(如本例),AtomicInteger
速度非常快,不会造成性能问题。但如果它担心您可以使用非线程安全计数器。)
回答by Tagir Valeev
One more solution just for completeness is to use custom collector:
仅出于完整性考虑的另一种解决方案是使用自定义收集器:
public static <T> Collector<T, ?, Map<Integer, T>> toMap() {
return Collector.of(HashMap::new, (map, t) -> map.put(map.size(), t),
(m1, m2) -> {
int s = m1.size();
m2.forEach((k, v) -> m1.put(k+s, v));
return m1;
});
}
Usage:
用法:
Map<Integer, Item> map = items.stream().collect(toMap());
This solution is parallel-friendly and does not depend on the source (you can use list without random access or Files.lines()
or whatever).
此解决方案是并行友好的,不依赖于源(您可以使用列表而无需随机访问Files.lines()
或其他)。
回答by njzk2
Using a third party library (protonpackfor example, but there are others) you can zip
the value with its index and voila:
使用第三方库(例如protonpack,但还有其他库),您可以zip
使用其索引和瞧:
StreamUtils.zipWithIndex(items.stream())
.collect(Collectors.toMap(Indexed::getIndex, Indexed::getValue));
although getIndex
returns a long
, so you may need to cast it using something similar to:
虽然getIndex
返回 a long
,因此您可能需要使用类似于以下内容的内容进行转换:
i -> Integer.valueOf((int) i.getIndex())
回答by Stuart Marks
Eran's answeris usually the best approach for random-access lists.
Eran 的答案通常是随机访问列表的最佳方法。
If your List
isn't random access, or if you have a Stream
instead of a List
, you can use forEachOrdered
:
如果您List
不是随机访问,或者您有 aStream
而不是 a List
,则可以使用forEachOrdered
:
Stream<Item> stream = ... ;
Map<Integer, Item> map = new HashMap<>();
AtomicInteger index = new AtomicInteger();
stream.forEachOrdered(item -> map.put(index.getAndIncrement(), item));
This is safe, if the stream is parallel, even though the destination map is thread-unsafe and is operated upon as a side effect. The forEachOrdered
guarantees that items are processed one-at-a-time, in order. For this reason it's unlikely that any speedup will result from running in parallel. (There might be some speedup if there are expensive operations in the pipeline before the forEachOrdered
.)
这是安全的,如果流是并行的,即使目标映射是线程不安全的并且作为副作用进行操作。在forEachOrdered
保证数据项都处理一个在-A-时,为了。出于这个原因,并行运行不太可能导致任何加速。(如果在forEachOrdered
.