Java 8列表与stream映射
我有一个List<Item>
集合。 我需要将其转换为Map<Integer, Item>
地图的关键字必须是集合中项目的索引。 我不知道如何做到这一点与stream。 就像是:
items.stream().collect(Collectors.toMap(...));
任何帮助?
由于这个问题被认为是可能的重复我需要补充一点,我的具体问题是 – 如何获得列表中的项目的位置,并把它作为一个关键的价值
您可以使用IntStream
创build索引Stream
,然后将其转换为Map
:
Map<Integer,Item> map = IntStream.range(0,items.size()) .boxed() .collect(Collectors.toMap (i -> i, i -> items.get(i)));
为了完整性,另一个解决scheme是使用自定义收集器:
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; }); }
用法:
Map<Integer, Item> map = items.stream().collect(toMap());
这个解决scheme是并行友好的,不依赖于源(你可以使用没有随机访问的列表或Files.lines()
或其他)。
不要觉得你必须在stream中做任何事情 。 我只会做:
AtomicInteger index = new AtomicInteger(); items.stream().collect(Collectors.toMap(i -> index.getAndIncrement(), i -> i));
只要你不平行stream,这将工作,它避免了可能昂贵和/或问题(在重复的情况下) get()
和indexOf()
操作。
(你不能使用一个常规的int
variables来代替AtomicInteger
因为从lambdaexpression式外部使用的variables必须是有效的final请注意,当无争议(在这种情况下), AtomicInteger
速度非常快,不会造成性能问题。但是,如果您担心,您可以使用非线程安全计数器。)
这是更新的答案,并没有在评论中提到的问题。
Map<Integer,Item> outputMap = IntStream.range(0,inputList.size()).boxed().collect(Collectors.toMap(Function.identity(), i->inputList.get(i)));
使用第三方库( protonpack例如,但也有其他),你可以用它的索引zip
值,瞧:
StreamUtils.zipWithIndex(items.stream()) .collect(Collectors.toMap(Indexed::getIndex, Indexed::getValue));
虽然getIndex
返回一个long
,所以你可能需要使用类似于下面的东西来施放它:
i -> Integer.valueOf((int) i.getIndex())
Eran的答案通常是随机访问列表的最佳方法。
如果您的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));
这是安全的,如果stream是平行的,即使目的地图是线程不安全的并且作为副作用被操作。 forEachOrdered
保证项目按顺序一次处理。 由于这个原因,并行运行速度不太可能会提高。 (如果在forEachOrdered
之前在stream水线中有昂贵的操作,那么可能会有一些加速。)