如何使用 Java 8 流根据值合并两个 Map?
我有一个包含库存信息的 Map
的 Collection
:
0
"subtype" -> "DAIRY"
"itemNumber" -> "EU999"
"quantity" -> "60"
1
"subtype" -> "DAIRY"
"itemNumber" -> "EU999"
"quantity" -> "1000"
2
"subtype" -> "FRESH"
"itemNumber" -> "EU999"
"quantity" -> "800"
3
"subtype" -> "FRESH"
"itemNumber" -> "EU100"
"quantity" -> "100"
我需要根据 itemNumber
压缩此列表,同时对 quantity 求和
并在逗号分隔的字符串中保留唯一的子类型
。意思是,新 Map
看起来像这样:
0
"subtype" -> "DAIRY, FRESH"
"itemNumber" -> "EU999"
"quantity" -> "1860"
1
"subtype" -> "FRESH"
"itemNumber" -> "EU100"
"quantity" -> "100"
我尝试了流、收集器、groupby 等的各种变体,但我迷路了。
这是我到目前为止所拥有的:
public Collection<Map> mergeInventoryPerItemNumber(Collection<Map> InventoryMap){
Map condensedInventory = null;
InventoryMap.stream()
.collect(groupingBy(inv -> new ImmutablePair<>(inv.get("itemNumber"), inv.get("subtype")))), collectingAndThen(toList(), list -> {
long count = list.stream()
.map(list.get(Integer.parseInt("quantity")))
.collect(counting());
String itemNumbers = list.stream()
.map(list.get("subtype"))
.collect(joining(" , "));
condensedInventory.put("quantity", count);
condensedInventory.put("subtype", itemNumbers);
return condensedInventory;
});
I have a Collection
of Map
s containing inventory information:
0
"subtype" -> "DAIRY"
"itemNumber" -> "EU999"
"quantity" -> "60"
1
"subtype" -> "DAIRY"
"itemNumber" -> "EU999"
"quantity" -> "1000"
2
"subtype" -> "FRESH"
"itemNumber" -> "EU999"
"quantity" -> "800"
3
"subtype" -> "FRESH"
"itemNumber" -> "EU100"
"quantity" -> "100"
I need to condense this list based on the itemNumber
, while summing the quantity
and retaining unique subtypes
in a comma separated string. Meaning, new Map
s would look like this:
0
"subtype" -> "DAIRY, FRESH"
"itemNumber" -> "EU999"
"quantity" -> "1860"
1
"subtype" -> "FRESH"
"itemNumber" -> "EU100"
"quantity" -> "100"
I've tried a variations of streams, collectors, groupby etc., and I'm lost.
This is what I have so far:
public Collection<Map> mergeInventoryPerItemNumber(Collection<Map> InventoryMap){
Map condensedInventory = null;
InventoryMap.stream()
.collect(groupingBy(inv -> new ImmutablePair<>(inv.get("itemNumber"), inv.get("subtype")))), collectingAndThen(toList(), list -> {
long count = list.stream()
.map(list.get(Integer.parseInt("quantity")))
.collect(counting());
String itemNumbers = list.stream()
.map(list.get("subtype"))
.collect(joining(" , "));
condensedInventory.put("quantity", count);
condensedInventory.put("subtype", itemNumbers);
return condensedInventory;
});
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是一种方法。
itemNumber
和quantity
itemNumber
是所有值的连接元素。quantity
是必须被视为整数的值一些数据
构建过程
打印
请注意,地图的地图可能比地图列表更有用。例如,您只需指定所需的键即可检索
itemNumber
的地图。印刷
Here is one approach.
itemNumber
andquantity
itemNumber
is the joining element for all the values.quantity
is the value that must be treated as an integerSome data
The building process
prints
Note that the map of maps may be more useful that a list of maps. For example, you can retrieve the map for the
itemNumber
by simply specifying the desired key.prints
您在这里滥用了
Map
。每个地图都包含相同的键(“subtype”、“itemNumber”、“quantity”)。它们在代码中几乎被视为对象属性。它们应该出现在每个地图中,并且每个地图都应该具有特定的值范围,尽管根据您的示例存储为字符串。旁注:避免使用行类型(例如
Map
,尖括号<>
中没有通用信息),在这样的情况下在这种情况下,集合中的所有元素都将被视为Object
。Item
显然必须定义为类。通过将这些数据存储在地图中,您将失去为每个属性定义适当的数据类型的可能性,而且您无法定义行为来操纵这些属性(有关更详细的解释,请查看这个答案)。方法
combine
表示将两个项目合并在一起的逻辑。通过将其放置在这个类中,您可以在需要时轻松重用和更改它。subtype
字段类型的最佳选择是 枚举。因为它可以避免由拼写错误的字符串值引起的错误,并且枚举具有广泛的语言支持(switch
表达式< /em>和语句,专门为枚举设计的特殊数据结构,enum可以与一起使用注释)。这个自定义枚举看起来像这样。
经过所有这些更改,
mergeInventoryPerItemNumber()
内的代码变得简洁且更易于理解。Collectors.groupingBy()
用于通过将具有相同itemNumber
的项目分组来创建地图。下游收集器Collectors.reducing()
用于将同一 key 下分组的项合并为一个单个对象 。请注意,
Collectors.reducing()
会生成一个Optional
结果。因此,使用filter(Optional::isPresent)
作为预防措施,以确保结果存在,并且后续操作map(Optional::get)
提取 来自可选对象的项目。main()
输出
You are misusing a
Map
here. Every map contains the same keys ("subtype", "itemNumber", "quantity"). And they are treated almost like object properties in your code. They are expected to be present in every map and each of them expected to have a specific range of values, although are stored as strings according to your example.Side-note: avoid using row types (like
Map
without generic information in angle brackets<>
), in such a case all elements inside a collection will be treated asObject
s.Item
clearly has to be defined as a class. By storing these data inside a map, you're loosing a possibility to define an appropriate data type for each property, and also you're not able to define behaviour to manipulate with these properties (for more elaborate explanation take a look at this answer).Method
combine
represents the logic for merging two items together. By placing it inside this class, you could easily reuse and change it when needed.The best choice for the type of the
subtype
field is an enum. Because it'll allow to avoid mistakes caused by misspelled string values and also enums have an extensive language support (switch
expressions and statements, special data structures designed especially for enums, enum could be used with annotations).This custom enum can look like this.
With all these changes, the code inside the
mergeInventoryPerItemNumber()
becomes concise and easier to comprehend.Collectors.groupingBy()
is used to create a map by grouping items with the sameitemNumber
. A downstream collectorCollectors.reducing()
is used to combine items grouped under the same key to a single object.Note that
Collectors.reducing()
produces anOptional
result. Therefore,filter(Optional::isPresent)
is used as a precaution to make sure that the result exists and subsequent operationmap(Optional::get)
extracts the item from the optional object.main()
Output
也许可以通过一次扫描来完成此操作,但在这里我通过两次传递解决了这个问题:一次将类似的项目分组在一起,另一次在每个组中的项目上构建一个代表性项目(这在精神上似乎与您的类似)代码,您还尝试从组中传输元素)。
It may be possible to do this with a single sweep, but here I have solved it with two passes: one to group like items together, and another over the items in each group to build a representative item (which seems similar in spirit to your code, where you were also attempting to stream elements from groups).