Java Streams:将列表分组为地图映射
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33253858/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java Streams: group a List into a Map of Maps
提问by mrod
How could I do the following with Java Streams?
我如何使用 Java Streams 执行以下操作?
Let's say I have the following classes:
假设我有以下课程:
class Foo {
Bar b;
}
class Bar {
String id;
String date;
}
I have a List<Foo>
and I want to convert it to a Map <Foo.b.id, Map<Foo.b.date, Foo>
. I.e: group first by the Foo.b.id
and then by Foo.b.date
.
我有一个List<Foo>
,我想将它转换为一个Map <Foo.b.id, Map<Foo.b.date, Foo>
. 即:首先分组Foo.b.id
,然后分组Foo.b.date
。
I'm struggling with the following 2-step approach, but the second one doesn't even compile:
我正在努力使用以下两步方法,但第二个方法甚至无法编译:
Map<String, List<Foo>> groupById =
myList
.stream()
.collect(
Collectors.groupingBy(
foo -> foo.getBar().getId()
)
);
Map<String, Map<String, Foo>> output = groupById.entrySet()
.stream()
.map(
entry -> entry.getKey(),
entry -> entry.getValue()
.stream()
.collect(
Collectors.groupingBy(
bar -> bar.getDate()
)
)
);
Thanks in advance.
提前致谢。
采纳答案by Flown
You can group your data in one go assuming there are only distinct Foo
:
假设只有不同的数据,您可以一次性对数据进行分组Foo
:
Map<String, Map<String, Foo>> map = list.stream()
.collect(Collectors.groupingBy(f -> f.b.id,
Collectors.toMap(f -> f.b.date, Function.identity())));
Saving some characters by using static imports:
使用静态导入保存一些字符:
Map<String, Map<String, Foo>> map = list.stream()
.collect(groupingBy(f -> f.b.id, toMap(f -> f.b.date, identity())));
回答by Alex Salauyou
Suppose (b.id, b.date)
pairs are distinct. If so,
in second step you don't need grouping, just collecting to Map
where key is foo.b.date
and value is foo
itself:
假设(b.id, b.date)
对是不同的。如果是这样,在第二步中,您不需要分组,只需收集到Map
key 所在的位置foo.b.date
, valuefoo
本身即可:
Map<String, Map<String, Foo>> map =
myList.stream()
.collect(Collectors.groupingBy(f -> f.b.id)) // map {Foo.b.id -> List<Foo>}
.entrySet().stream()
.collect(Collectors.toMap(e -> e.getKey(), // id
e -> e.getValue().stream() // stream of foos
.collect(Collectors.toMap(f -> f.b.date,
f -> f))));
Or even more simple:
或者更简单:
Map<String, Map<String, Foo>> map =
myList.stream()
.collect(Collectors.groupingBy(f -> f.b.id,
Collectors.toMap(f -> f.b.date,
f -> f)));
回答by weston
An alternative is to support the equality contract on your key, Bar
:
另一种选择是支持您的密钥上的平等合同,Bar
:
class Bar {
String id;
String date;
public boolean equals(Object o){
if (o == null) return false;
if (!o.getClass().equals(getClass())) return false;
Bar other = (Bar)o;
return Objects.equals(o.id, id) && Objects.equals(o.date, date);
}
public int hashCode(){
return id.hashCode*31 + date.hashCode;
}
}
Now you can just have a Map<Bar, Foo>
.
现在你可以只拥有一个Map<Bar, Foo>
.