Java8列表与流映射

Java8列表与流映射,java,dictionary,collections,java-8,java-stream,Java,Dictionary,Collections,Java 8,Java Stream,我有一个列表收藏。 我需要将其转换为Map 映射的键必须是集合中项的索引。 我不知道如何使用流来实现这一点。 比如: items.stream().collect(Collectors.toMap(...)); 有什么帮助吗 由于这个问题被确定为可能重复,我需要补充一点,我的具体问题是-如何获取列表中项目的位置并将其作为键值您可以使用IntStream创建索引的流,然后将其转换为映射: Map<Integer,Item> map = IntStream.range(0,i

我有一个
列表
收藏。 我需要将其转换为
Map
映射的键必须是集合中项的索引。 我不知道如何使用流来实现这一点。 比如:

items.stream().collect(Collectors.toMap(...));
有什么帮助吗


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

您可以使用
IntStream
创建索引的
,然后将其转换为
映射

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

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

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

不要觉得你必须在流中做任何事情。我只想:

AtomicInteger index = new AtomicInteger();
items.stream().collect(Collectors.toMap(i -> index.getAndIncrement(), i -> i));
只要您不并行化流,这将起作用,并且它避免了潜在的昂贵和/或问题(在重复的情况下)
get()
indexOf()
操作


(不能使用正则
int
变量代替
AtomicInteger
,因为从lambda表达式外部使用的变量必须是有效的最终变量。请注意,在无竞争时(如本例中),
AtomicInteger
速度非常快,不会造成性能问题。但如果担心,您可以使用非线程安全计数器。)

为了完整起见,还有一个解决方案是使用自定义收集器:

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;
            });
}
公共静态收集器toMap(){
返回Collector.of(HashMap::new,(map,t)->map.put(map.size(),t),
(m1,m2)->{
ints=m1.size();
m2.forEach((k,v)->m1.put(k+s,v));
返回m1;
});
}
用法:

Map<Integer, Item> map = items.stream().collect(toMap());
Map-Map=items.stream().collect(toMap());

此解决方案是并行友好的,不依赖于源代码(您可以使用无随机访问的列表或
文件.lines()
或其他任何内容)。

使用第三方库(例如,但也有其他库),您可以
zip
带索引的值,瞧:

StreamUtils.zipWithIndex(items.stream())
    .collect(Collectors.toMap(Indexed::getIndex, Indexed::getValue));
虽然
getIndex
返回一个
long
,但您可能需要使用类似以下内容来强制转换它:

i -> Integer.valueOf((int) i.getIndex())
通常是随机访问列表的最佳方法

如果您的
列表
不是随机访问,或者如果您有
而不是
列表
,则可以使用
forEachOrdered

Stream<Item> stream = ... ;
Map<Integer, Item> map = new HashMap<>();
AtomicInteger index = new AtomicInteger();
stream.forEachOrdered(item -> map.put(index.getAndIncrement(), item));
Stream=;
Map Map=newhashmap();
AtomicInteger索引=新的AtomicInteger();
stream.forEachOrdered(item->map.put(index.getAndIncrement(),item));

如果流是并行的,那么这是安全的,即使目标映射是线程不安全的,并且作为副作用操作。
forEachOrdered
保证按顺序一次处理一个项目。由于这个原因,并行运行不太可能导致任何加速。(如果在
forEachOrdered
)或
EntryStream.of(items).toMap()之前的管道中存在昂贵的操作,则可能会有一些加速)使用我的免费库。JavaDoc是。对这个问题做了一些研究,我发现在Java8流中竟然没有
zip
。@njzk2,这只是因为你不能并行压缩流。拥有随机访问源(例如,两个
ArrayList
),通过
IntStream.range(0,list1.size()).mapToObj(idx->doSomethingWith(list1.get(idx),list2.get(idx))压缩它们并不困难
并且结果将是并行友好的如果列表中重复了
,则此操作将失败。不要对大型列表执行此操作。除非你想通过例子学习,否则
O(n²)
的意思是……
list.indexOf(i)
很慢。我不建议使用这种方法。这种方法有太多的限制和低效,因此它不是一种有用的解决方案。您称之为
List.get()
昂贵,但建议使用
AtomicInteger
?@Holger否。我称之为
List.get()
可能昂贵
AtomicInteger
是O(1),
List.get()
可以是O(n)以下的任何值。仅当您使用的是
LinkedList
时,这并不是真正有用的。另一方面,
AtomicInteger
成为
O(1)
在一个你承认不能并行工作的操作中,涉及到线程安全的隐藏成本时,其实并不相关。如果你的答案是“不要觉得你必须在流中做任何事情”,为什么不提供一个无流的替代方案,比如一个直接的循环?这比不鼓励流使用要好…@Holger OP没有指定
列表
实现。您似乎对
LinkedList
抱有偏见,但事实上它并没有错,
列表可能是其中之一,甚至可能是另一个更昂贵的实现。为什么要怀疑呢?这种方式永远是最快的。我并不反对
LinkedList
,因为它已经存在了15年多了,这足够时间来确定它在现实生活中没有用处。理论上的优势只是一个操作,即在任意索引处插入,但由于它必须为此分配内存并更新六个节点引用,因此这一优势并没有真正实现。它需要非常大的列表来输出
ArrayList
,但是对于大列表,
LinkedList
的疯狂内存开销将起到反作用
LinkedList
仅在
O(…)
比较中获胜,该比较忽略了一旦
就停止工作的记忆效应