简体   繁体   English

用流映射的Java 8列表

[英]Java 8 list to map with stream

I have a List<Item> collection. 我有一个List<Item>集合。 I need to convert it into Map<Integer, Item> The key of the map must be the index of the item in the collection. 我需要将其转换为Map<Integer, Item>映射的键必须是集合中项的索引。 I can not figure it out how to do this with streams. 我无法弄清楚如何使用流来做到这一点。 Something like: 就像是:

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 由于这个问题被确定为可能重复,我需要补充一点,我的具体问题是 - 如何获取列表中项目的位置并将其作为键值

You can create a Stream of the indices using an IntStream and then convert them to a Map : 您可以使用IntStream创建索引Stream ,然后将它们转换为Map

Map<Integer,Item> map = 
    IntStream.range(0,items.size())
             .boxed()
             .collect(Collectors.toMap (i -> i, i -> items.get(i)));

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()或其他)。

Don't feel like you have to do everything in/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非常快,不会造成性能问题。但如果它让你担心,你可以使用非线程安全的计数器。)

这是更新的答案,没有评论中提到的问题。

Map<Integer,Item> outputMap = IntStream.range(0,inputList.size()).boxed().collect(Collectors.toMap(Function.identity(), i->inputList.get(i)));

Using a third party library ( protonpack for example, but there are others) you can zip the value with its index and voila: 使用第三方库(例如protonpack ,但还有其他库),您可以使用其索引和voilazip值:

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返回一个long ,所以你可能需要使用类似的东西来强制转换:

i -> Integer.valueOf((int) i.getIndex())

Eran's answer is 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不是随机访问,或者您有Stream而不是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. forEachOrdered保证按顺序一次一个地处理项目。 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之前管道中有昂贵的操作,可能会有一些加速。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM