Flatten a Maplt;Integer, Listlt;Stringgt;gt; to Maplt;String, Integergt; with stream and lambda(展平地图lt;整数,列表lt;字符串gt;gt;映射lt;字符串,整数gt;带流和 lambda)
问题描述
我想展平一个 Map
,它将 Integer
键关联到 String
列表,而不会丢失键映射.我很好奇,好像使用 stream
和 lambda
这样做是可能和有用的.
I would like to flatten a Map
which associates an Integer
key to a list of String
, without losing the key mapping.
I am curious as though it is possible and useful to do so with stream
and lambda
.
我们从这样的开始:
Map<Integer, List<String>> mapFrom = new HashMap<>();
让我们假设 mapFrom 填充在某个地方,看起来像:
Let's assume that mapFrom is populated somewhere, and looks like:
1: a,b,c
2: d,e,f
etc.
我们还假设列表中的值是唯一的.
Let's also assume that the values in the lists are unique.
现在,我想展开"它以获得第二张地图,例如:
Now, I want to "unfold" it to get a second map like:
a: 1
b: 1
c: 1
d: 2
e: 2
f: 2
etc.
我可以这样做(或者非常类似,使用 foreach
):
I could do it like this (or very similarly, using foreach
):
Map<String, Integer> mapTo = new HashMap<>();
for (Map.Entry<Integer, List<String>> entry: mapFrom.entrySet()) {
for (String s: entry.getValue()) {
mapTo.put(s, entry.getKey());
}
}
现在让我们假设我想使用 lambda 而不是嵌套的 for
循环.我可能会这样做:
Now let's assume that I want to use lambda instead of nested for
loops. I would probably do something like this:
Map<String, Integer> mapTo = mapFrom.entrySet().stream().map(e -> {
e.getValue().stream().?
// Here I can iterate on each List,
// but my best try would only give me a flat map for each key,
// that I wouldn't know how to flatten.
}).collect(Collectors.toMap(/*A String value*/,/*An Integer key*/))
我也尝试了flatMap
,但我认为这不是正确的方法,因为虽然它可以帮助我摆脱维度问题,但我失去了关键过程.
I also gave a try to flatMap
, but I don't think that it is the right way to go, because although it helps me get rid of the dimensionality issue, I lose the key in the process.
简而言之,我的两个问题是:
In a nutshell, my two questions are :
- 是否可以使用
streams
和lambda
来实现? - 这样做是否有用(性能、可读性)?
推荐答案
您需要使用 flatMap
将值扁平化到一个新的流中,但是由于您仍然需要原始键来收集到一个Map
,你必须映射到一个持有key和value的临时对象,例如
You need to use flatMap
to flatten the values into a new stream, but since you still need the original keys for collecting into a Map
, you have to map to a temporary object holding key and value, e.g.
Map<String, Integer> mapTo = mapFrom.entrySet().stream()
.flatMap(e->e.getValue().stream()
.map(v->new AbstractMap.SimpleImmutableEntry<>(e.getKey(), v)))
.collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
Map.Entry
是不存在的元组类型的替代,任何其他能够容纳两个不同类型对象的类型都足够了.
The Map.Entry
is a stand-in for the nonexistent tuple type, any other type capable of holding two objects of different type is sufficient.
另一种不需要这些临时对象的方法是自定义收集器:
An alternative not requiring these temporary objects, is a custom collector:
Map<String, Integer> mapTo = mapFrom.entrySet().stream().collect(
HashMap::new, (m,e)->e.getValue().forEach(v->m.put(v, e.getKey())), Map::putAll);
这与 toMap
的不同之处在于静默覆盖重复键,而没有合并函数的 toMap
如果存在重复键,则会抛出异常.基本上,这个自定义收集器是一个具有并行能力的变体
This differs from toMap
in overwriting duplicate keys silently, whereas toMap
without a merger function will throw an exception, if there is a duplicate key. Basically, this custom collector is a parallel capable variant of
Map<String, Integer> mapTo = new HashMap<>();
mapFrom.forEach((k, l) -> l.forEach(v -> mapTo.put(v, k)));
但请注意,即使输入图非常大,此任务也不会从并行处理中受益.只有当流管道中有额外的计算密集型任务可以从 SMP 中受益时,才有机会从并行流中受益.因此,简洁、顺序的 Collection API 解决方案或许更可取.
But note that this task wouldn’t benefit from parallel processing, even with a very large input map. Only if there were additional computational intense task within the stream pipeline that could benefit from SMP, there was a chance of getting a benefit from parallel streams. So perhaps, the concise, sequential Collection API solution is preferable.
这篇关于展平地图<整数,列表<字符串>>映射<字符串,整数>带流和 lambda的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:展平地图<整数,列表<字符串>>映射<字符串,整数>带流和 lambda
基础教程推荐
- Java Keytool 导入证书后出错,"keytool error: java.io.FileNotFoundException &拒绝访问" 2022-01-01
- 无法使用修饰符“public final"访问 java.util.Ha 2022-01-01
- 如何使用 Java 创建 X509 证书? 2022-01-01
- Java:带有char数组的println给出乱码 2022-01-01
- 降序排序:Java Map 2022-01-01
- 在 Libgdx 中处理屏幕的正确方法 2022-01-01
- “未找到匹配项"使用 matcher 的 group 方法时 2022-01-01
- FirebaseListAdapter 不推送聊天应用程序的单个项目 - Firebase-Ui 3.1 2022-01-01
- 设置 bean 时出现 Nullpointerexception 2022-01-01
- 减少 JVM 暂停时间 >1 秒使用 UseConcMarkSweepGC 2022-01-01