首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Java 8 lambda:将集合转换为元素的映射,迭代位置

Java 8 lambda:将集合转换为元素的映射,迭代位置
EN

Stack Overflow用户
提问于 2014-07-30 23:44:04
回答 6查看 13.1K关注 0票数 9

如何将"a","b","c“这样的集合转换为{"a":0,"b":1,"c":2}这样的映射,值是迭代的顺序。在JDK8中有没有包含流和收集器的一体机?老办法是这样的:

代码语言:javascript
运行
复制
    Collection<String> col = apiCall();
    Map<String, Integer> map = new HashMap<>();
    int pos = 0;
    for (String s : collection) {
        map.put(s, pos++);
    }
EN

回答 6

Stack Overflow用户

发布于 2014-07-31 00:01:11

如果你不需要并行流,你可以使用map的长度作为索引计数器:

代码语言:javascript
运行
复制
collection.stream().forEach(i -> map.put(i, map.size() + 1));
票数 6
EN

Stack Overflow用户

发布于 2014-07-31 01:08:46

这是一种方法:

代码语言:javascript
运行
复制
List<String> list = Arrays.asList("a", "b", "c");

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

不一定是一行或比直接循环更短的循环,但如果您将toMap更改为toConcurrentMap,它确实可以使用并行流。

还要注意,这里假设您有一个随机访问列表,而不是一个通用的Collection。如果您有一个无法对其进行任何假设的Collection,那么除了顺序地迭代它并递增一个计数器之外,您没有什么可做的。

更新

OP已经澄清了输入是Collection而不是List,所以上面的内容不适用。似乎我们对输入Collection的假设很少。操作已指定迭代顺序。使用顺序迭代器,元素将以某种顺序出现,尽管不能保证这一点。它可能会从一个运行到另一个运行,甚至从一个迭代到下一个迭代(尽管这在实践中是不常见的--除非底层集合被修改)。

如果需要保留确切的迭代顺序,我认为没有办法在不按顺序迭代输入Collection的情况下将其保留到结果Map中。

但是,如果准确的迭代顺序并不重要,并且要求输出Map对每个输入元素都有唯一的值,则可以并行执行以下操作:

代码语言:javascript
运行
复制
Collection<String> col = apiCall();
Iterator<String> iter = col.iterator();

Map<String, Integer> map =
    IntStream.range(0, col.size())
        .parallel()
        .boxed()
        .collect(toConcurrentMap(i -> { synchronized (iter) { return iter.next(); }},
                                 i -> i));

现在,这远远不是一行代码。我也不清楚它有多有用。:-)但它确实证明了可以并行地做这样的事情。请注意,我们必须同步对输入集合的迭代器的访问,因为它将从多个线程调用。还要注意,这是迭代器的一种不寻常的用法,因为我们从未调用过hasNext,并且我们假设调用next的次数与输入集合的size()返回的次数完全相同是安全的。

票数 6
EN

Stack Overflow用户

发布于 2014-07-31 23:23:46

基于maba’s answer的一般解决方案是:

代码语言:javascript
运行
复制
collection.stream().forEachOrdered(i -> map.put(i, map.size()));

documentation of void forEachOrdered(Consumer action)

此操作一次处理一个元素,如果存在元素,则按相遇顺序处理。

这里重要的方面是,如果存在一个顺序,例如,如果CollectionSortedSetList,它将保留顺序。这样的流被称为有序流(不要与排序流混淆)。它可以通过不同的线程调用使用者方法,但始终确保“一次一个”和线程安全保证。

当然,如果流是并行的,那么它不会从并行执行中受益。

为了完整起见,这里是一个解决方案,即使在使用并行处理的并行流上也可以工作,如果它们仍然是有序的

代码语言:javascript
运行
复制
stream.collect(HashMap::new, (m, i) -> m.put(i, m.size()),
  (a, b) -> {int offset = a.size(); b.forEach((k, v) -> a.put(k, v + offset));});
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25041177

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档