我有以下数据:
List<Map<String, Object>> products = new ArrayList<>();
Map<String, Object> product1 = new HashMap<>();
product1.put("Id", 1);
product1.put("number", "123");
product1.put("location", "ny");
Map<String, Object> product2 = new HashMap<>();
product2.put("Id", 1);
product2.put("number", "456");
product2.put("location", "ny");
Map<String, Object> product3 = new HashMap<>();
product3.put("Id", 2);
product3.put("number", "789");
product3.put("location", "ny");
products.add(product1);
products.add(product2);
products.add(product3);
我尝试在产品列表上流式传输,按ID分组,每个ID都有一个数字列表,同时返回包含三个键的地图:Id,数字列表和位置。< / p>
所以我的输出是:
List<Map<String, Object>>> groupedProducts
map[0]
{id:1, number[123,456], location:ny}
map[1]
{id:2, number[789], location:ny}
我试过了:
Map<String, List<Object>> groupedProducts = products.stream()
.flatMap(m -> m.entrySet().stream())
.collect(groupingBy(Entry::getKey, mapping(Entry::getValue, toList())));
打印:
{number=[123, 456, 789], location=[ny, ny, ny], Id=[1, 1, 2]}
我意识到Map<String, List<Object>>
不正确,但它是我能够实现的最佳流程。任何反馈都表示赞赏。
答案 0 :(得分:2)
在您的情况下,Id
键与Collectors.collectingAndThen(downstream, finisher)
分组可以解决问题。请考虑以下示例:
Collection<Map<String, Object>> finalMaps = products.stream()
.collect(groupingBy(it -> it.get("Id"), Collectors.collectingAndThen(
Collectors.toList(),
maps -> (Map<String, Object>) maps.stream()
.reduce(new HashMap<>(), (result, map) -> {
final List<Object> numbers = (List<Object>) result.getOrDefault("number", new ArrayList<>());
result.put("Id", map.getOrDefault("Id", result.getOrDefault("Id", null)));
result.put("location", map.getOrDefault("location", result.getOrDefault("location", null)));
if (map.containsKey("number")) {
numbers.add(map.get("number"));
}
result.put("number", numbers);
return result;
}))
)
)
.values();
System.out.println(finalMaps);
在第一步中,您将具有相同Id
值的所有地图分组到List<Map<String,Object>>
(这是Collectors.toList()
传递给.collectingAndThen()
的地图。创建该列表&#34;终结者&#34;调用函数 - 在这种情况下,我们使用Stream.reduce()
操作将地图列表转换为单个地图 - 我们从空HashMap<String,Object>
开始,我们迭代地图,在迭代中从当前地图获取值并设置值根据您的规范(&#34; Id&#34;和&#34;位置&#34;被覆盖,&#34;数字&#34;保留值列表)。
[{number=[123, 456], location=ny, Id=1}, {number=[789], location=ny, Id=2}]
为了使代码更简单,您可以将传递给BiOperator
的{{1}}提取到方法并改为使用方法引用。这个函数定义了将两个映射组合成单个映射的意义,因此它是整个映射的核心逻辑。