Java流 - 组合并返回嵌套地图
我的数据就是这样,
unitId time value1 value2
a 2021 10 11
a 2022 15 13
b 2021 20 25
b 2022 30 37
我的目标是将每个unitid和价值放入这样的地图中,
{
'a': {'2021_value1': 10, '2021_value2': 11, '2022_value1': 15, '2022_value2': 13},
'b': {'2021_value1': 20, '2021_value2': 25, '2022_value1': 30, '2022_value2': 37},
}
我已经找出了两种实现这一目标的方法,这是我的代码,
public class Unit {
public String unitId;
public Integer year;
public Integer value1;
public Integer value2;
public static Unit of(String unitId, Integer year, Integer value1, Integer value2) {
Unit unit = new Unit();
unit.unitId = unitId;
unit.year = year;
unit.value1 = value1;
unit.value2 = value2;
return unit;
}
}
第
public class UnitTest {
private static void printMap(Map<String, Map<String, Integer>> map) {
map.forEach((k, v) -> {
String vStr = v.entrySet().stream().map(a -> String.format("%s: %s", a.getKey(), a.getValue())).collect(Collectors.joining(", "));
System.out.printf("%s: {%s}%n", k, vStr);
});
}
public static void main(String[] args) {
List<Unit> list = new ArrayList<>();
list.add(Unit.of("a", 2021, 10, 11 ));
list.add(Unit.of("a", 2022, 15, 13));
list.add(Unit.of("b", 2021, 20, 25));
list.add(Unit.of("b", 2022, 30, 37));
Map<String, Map<String, Integer>> map1 = list.stream().collect(
Collectors.groupingBy(
x -> x.unitId,
Collector.of(
HashMap::new,
(x, y) -> {
x.put(String.format("%s_%s", y.year, "value1"), y.value1);
x.put(String.format("%s_%s", y.year, "value2"), y.value2);
},
(x, y) -> {x.putAll(y); return x;}
)
)
);
Map<String, Map<String, Integer>> map2 = list.stream().collect(
Collectors.groupingBy(
x -> x.unitId,
Collectors.collectingAndThen(
Collectors.toList(),
x -> x.stream()
.flatMap(y -> Stream.of(
new AbstractMap.SimpleEntry<>(String.format("%s_%s", y.year, "value1"), y.value1),
new AbstractMap.SimpleEntry<>(String.format("%s_%s", y.year, "value2"), y.value2)
))
.collect(Collectors.toMap(
AbstractMap.SimpleEntry::getKey,
AbstractMap.SimpleEntry::getValue)))
)
);
printMap(map1);
printMap(map2);
}
}
一个更像是手动编写处理,第二个使用临时的方法可能不需要的列表。是否有任何直接或简单的方法可以执行此操作,例如使用 collectors.tomap api或其他东西?
my data is like this,
unitId time value1 value2
a 2021 10 11
a 2022 15 13
b 2021 20 25
b 2022 30 37
my goal is put every unitId and value into a map like this,
{
'a': {'2021_value1': 10, '2021_value2': 11, '2022_value1': 15, '2022_value2': 13},
'b': {'2021_value1': 20, '2021_value2': 25, '2022_value1': 30, '2022_value2': 37},
}
I already figure out two ways to achieve that, here is my code,
public class Unit {
public String unitId;
public Integer year;
public Integer value1;
public Integer value2;
public static Unit of(String unitId, Integer year, Integer value1, Integer value2) {
Unit unit = new Unit();
unit.unitId = unitId;
unit.year = year;
unit.value1 = value1;
unit.value2 = value2;
return unit;
}
}
and,
public class UnitTest {
private static void printMap(Map<String, Map<String, Integer>> map) {
map.forEach((k, v) -> {
String vStr = v.entrySet().stream().map(a -> String.format("%s: %s", a.getKey(), a.getValue())).collect(Collectors.joining(", "));
System.out.printf("%s: {%s}%n", k, vStr);
});
}
public static void main(String[] args) {
List<Unit> list = new ArrayList<>();
list.add(Unit.of("a", 2021, 10, 11 ));
list.add(Unit.of("a", 2022, 15, 13));
list.add(Unit.of("b", 2021, 20, 25));
list.add(Unit.of("b", 2022, 30, 37));
Map<String, Map<String, Integer>> map1 = list.stream().collect(
Collectors.groupingBy(
x -> x.unitId,
Collector.of(
HashMap::new,
(x, y) -> {
x.put(String.format("%s_%s", y.year, "value1"), y.value1);
x.put(String.format("%s_%s", y.year, "value2"), y.value2);
},
(x, y) -> {x.putAll(y); return x;}
)
)
);
Map<String, Map<String, Integer>> map2 = list.stream().collect(
Collectors.groupingBy(
x -> x.unitId,
Collectors.collectingAndThen(
Collectors.toList(),
x -> x.stream()
.flatMap(y -> Stream.of(
new AbstractMap.SimpleEntry<>(String.format("%s_%s", y.year, "value1"), y.value1),
new AbstractMap.SimpleEntry<>(String.format("%s_%s", y.year, "value2"), y.value2)
))
.collect(Collectors.toMap(
AbstractMap.SimpleEntry::getKey,
AbstractMap.SimpleEntry::getValue)))
)
);
printMap(map1);
printMap(map2);
}
}
First one more like write the processing manually, second one uses temporary lists which may not be necessary. Is there any direct or simple way to do this, like use Collectors.toMap API or something else?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果您只想使用内置的收集器,则可以尝试
groupingby()
andteeing()
。collector.teeing()
期望三个参数:2
downstream collectors 和合并
函数。流中的每个元素都将传递到两个 collector 中,当完成这些收集器时,它们产生的结果将通过函数合并。在下面的代码中,
tomap()
用作teeing()
的下游收集器。这些收集器均负责检索其 value 的类型。该代码可能看起来像这样:
output:
注意:
collector.of()
会更好,因为它不喜欢t创建中间收藏。unitID
和年
的每种组合应该是唯一的。否则,请考虑添加用于解决重复项的逻辑。If you want to utilize only built-in collectors, you might try a combination of
groupingBy()
andteeing()
.Collectors.teeing()
expects three arguments:2
downstream collectors and amerger
function. Each element from the stream will be passed into both collectors, and when these collectors are done, results produced by them will get merged by the function.In the code below,
toMap()
is used as both downstream collectors ofteeing()
. And each of these collectors is responsible for retrieving its type of value.The code might look like that:
Output:
Note:
Collector.of()
would be slightly better because it doesn't create intermediate collections.unitId
andyear
should be unique. Otherwise, consider adding a logic for resolving duplicates.