dan*_*ial 9 java lambda java-8 java-stream
如何将像["a","b","c"]这样的集合转换为像{"a":0,"b":1,"c":2}这样的地图,其值为迭代.在JDK8中是否有一个带流和收集器的衬里?旧时尚的方式是这样的:
Collection<String> col = apiCall();
Map<String, Integer> map = new HashMap<>();
int pos = 0;
for (String s : collection) {
map.put(s, pos++);
}
Run Code Online (Sandbox Code Playgroud)
它不需要并行流,您可以使用地图的长度作为索引计数器:
collection.stream().forEach(i -> map.put(i, map.size() + 1));
Run Code Online (Sandbox Code Playgroud)
这是一种方法:
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));
Run Code Online (Sandbox Code Playgroud)
不一定是单行或短于简单的循环,但如果你改变toMap到它,它确实使用并行流toConcurrentMap.
另请注意,这假设您有一个随机访问列表,而不是一般Collection.如果你有一个Collection你不能做任何假设的事情,除了按顺序迭代它并增加一个计数器之外你没有什么可做的.
UPDATE
OP已澄清输入是a Collection而不是a,List因此上述不适用.似乎我们对输入的假设很少Collection.OP已指定迭代顺序.使用顺序迭代器,元素将以某种顺序出现,但不能保证它.它可能会在不同的运行之间发生变化,甚至从一次迭代变为另一次迭代(尽管这在实践中是不寻常的 - 除非底层集合被修改).
如果需要保留精确的迭代顺序,我不相信有一种方法可以将其保留到结果中Map而不会Collection顺序迭代输入.
但是,如果确切的迭代顺序并不重要,并且要求输出Map具有每个输入元素的唯一值,那么可以并行执行类似的操作:
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));
Run Code Online (Sandbox Code Playgroud)
现在这远远不是单行.我也不清楚它有多有用.:-)但它确实表明可以并行执行类似的操作.请注意,我们必须同步访问输入集合的迭代器,因为它将从多个线程调用.另请注意,这是迭代器的一种不寻常的用法,因为我们从不调用,hasNext并且我们假设next完全调用输入集合返回的次数是安全的size().
尝试
int[] pos = { 0 };
list.forEach( a -> map.put(a, pos[0]++));
Run Code Online (Sandbox Code Playgroud)