如何使用流将元素映射到其索引?

2022-09-03 09:56:38

我得到了一些自定义对象的流,我想创建一个映射,每个对象的索引作为键。举个简单的例子:Map<Integer, MyObject>

Stream<String> myStream = Arrays.asList("one","two","three").stream();
Integer i = 0;
Map<Integer, String> result3 = myStream.collect(Collectors.toMap(x -> i++, x -> x));

显然,这不会编译,因为:

从 lambda 表达式引用的局部变量必须是最终变量或实际上是最终变量

有没有一种简单的方法可以将流的 elemnts 映射到它们的索引,以便上述示例的预期输出如下所示:

{1=one, 2=two, 3=three}

答案 1

您可以使用 IntStream 来解决此问题:

List<String> list = Arrays.asList("one","two","three");
Map<Integer, String> map = IntStream.range(0, list.size()).boxed()
        .collect(Collectors.toMap(Function.identity(), list::get));

创建一个 from to (IntStream.range() 从流中排除最后一个值),并将每个索引映射到列表中的值。此解决方案的优点是,它还可以与并行流一起使用,而使用 .IntStream0list.size() - 1AtomicInteger

因此,在这种情况下,结果将是:

{0=one, 1=two, 2=three}

要在 处开始第一个索引,只需在收集期间添加:11

List<String> list = Arrays.asList("one", "two", "three");
Map<Integer, String> map = IntStream.range(0, list.size()).boxed()
        .collect(Collectors.toMap(i -> i + 1, list::get));

这将导致:

{1=one, 2=two, 3=three}

答案 2

您的变量实际上不是最终的。i

您可以使用 AtomicInteger 作为包装器:Integer

Stream<String> myStream = Arrays.asList("one","two","three").stream();
AtomicInteger atomicInteger = new AtomicInteger(0);
Map<Integer, String> result3 = myStream.collect(Collectors.toMap(x -> atomicInteger.getAndIncrement(), Function.identity()));

我认为它有点笨拙,因为它只能有效地解决最终变量的问题。由于它是一个特殊的 ThreadSafe 版本,它可能会引入一些开销。塞缪尔·菲利普(Samuel Philipp)的答案中的纯解决方案可能更适合您的需求。stream


推荐