用流映射的Java 8列表

Nik*_*lay 49 java collections dictionary java-8 java-stream

我有一个List<Item>集合.我需要将其转换Map<Integer, Item> 为映射的键必须是集合中项的索引.我无法弄清楚如何使用流来做到这一点.就像是:

items.stream().collect(Collectors.toMap(...));
Run Code Online (Sandbox Code Playgroud)

有帮助吗?

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

Era*_*ran 50

您可以使用a创建一个Stream索引IntStream,然后将它们转换为Map:

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


Tag*_*eev 12

另一个完整性的解决方案是使用自定义收集器:

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;
            });
}
Run Code Online (Sandbox Code Playgroud)

用法:

Map<Integer, Item> map = items.stream().collect(toMap());
Run Code Online (Sandbox Code Playgroud)

此解决方案是并行友好的,不依赖于源(您可以使用列表而无需随机访问Files.lines()或其他).


Pep*_*itz 9

不要觉得你必须在流中做任何事情.我会这样做:

AtomicInteger index = new AtomicInteger();
items.stream().collect(Collectors.toMap(i -> index.getAndIncrement(), i -> i));
Run Code Online (Sandbox Code Playgroud)

只要您不对流进行并行化,这将起作用,并且它避免了潜在的昂贵和/或有问题(在重复的情况下)get()indexOf()操作.

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

  • 你调用`List.get()`昂贵,但建议使用`AtomicInteger`? (4认同)
  • @Holger号我调用`List.get()`*可能*贵.`AtomicInteger`是O(1),`List.get()`可以是O(n)之前的任何东西. (4认同)
  • 只有当你使用`LinkedList`时才真正有用.另一方面,当你承认自己承认的操作中的线程安全隐藏成本时,`AtomicInteger`为'O(1)`并不真正相关,并不是并行工作.如果您开始回答"不要觉得您必须在流中/处理流中的所有内容",为什么不提供无流量替代方案,例如直接循环?这比提出不鼓励的流使用更好...... (3认同)
  • @Holger OP没有指定`List`实现.你似乎对`LinkedList`有偏见,但当然实际上它没有任何问题,`List`很容易就是一个,甚至可能是另一个更昂贵的实现.为什么要猜第二呢?这种方式总是最快的. (2认同)
  • 我不会*反对`LinkedList`,因为它已经存在超过15年了,这足以确定它在现实生活中没用.理论上的优势只是一个操作,插入一个任意索引,但由于它必须为此分配内存并更新六个节点引用,这种优势并没有真正实现.它需要非常大的列表才能超越`ArrayList`,但是对于大型列表,`LinkedList`的疯狂内存开销将反作用它.`LinkedList`仅在忽略记忆效应的'O(...)`比较中获胜 (2认同)

i_a*_*ero 7

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

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

  • 不要对大型列表执行此操作.除非你想通过实例学习,"O(n²)"意味着...... (11认同)
  • 如果在列表中重复"Item",则这将失败. (5认同)