# Java 8查询 – 基于多个对象列表的关键字分组计算

go评论50阅读模式

Java 8 Query - Grouping calculation based on Key with Multiple Lists of Objects

# 问题

(列表)

(列表)

``````for (Item item : Items) {
List<Tax> taxes = item.getTaxes;
for (Tax tax : taxes) {
createTax(Tax tax);
}
}

private void createTax(Tax tax) {
if (!taxAggreg.isEmpty() && taxAggreg.containsKey(tax.getTaxId())) {
Aggregate aggreg = taxAggreg.get(tax.getTaxId());
taxAggreg.put(tax.getTaxId(), aggreg);
} else {
taxAggreg.put(tax.getTaxId(), new Aggregate(tax.getTaxId(), tax.getName(),
tax.getTaxAmount()));
}
}
``````

I needed some help with a Java 8 solution to calculate totals.<br>
Suppose that I have 3 item objects and each of these objects contain a list of (2 or 3) tax objects. Please find below a detailed imaging of this object -

Item 1<br>
(List)<br>
Tax 1 - Id-1 | Name-A | Desc | Amount-Rs.5 | More objects<br>
Tax 2 - Id-2 | Name-B | Desc | Amount-Rs.10 | More objects<br>
Tax 3 - Id-3 | Name-C | Desc | Amount-Rs.8 | More objects<br>
<br>
Item 2<br>
(List)<br>
Tax 1 - Id-1 | Name-A | Desc | Amount-Rs.9 | More objects<br>
Tax 3 - Id-3 | Name-C | Desc | Amount-Rs.10 | More objects<br>

Now,<br>
I have created a new Object (Aggregate) that needs to be the total based on Id<br>
For ex: The above information should be have 3 aggregate objects with amounts summed <br>
Tax-1 | Name-A | Desc | Amount-Rs.14<br>
Tax-2 | Name-B | Desc | Amount-Rs.10<br>
Tax-2 | Name-B | Desc | Amount-Rs.18<br>
<br>
I was able to achieve this by looping through each object and adding it to a map <String Id,Object Aggregate>. If the keys existed, I would pull out the amount value from the Object Aggregate and add the amount to the existing amount. If not, I would create a new Aggregate object and add it to the map but I was hoping if there was a more optimised way to do this in Java 8<br>

Global variable - `Map&lt;String, Aggregate&gt; taxAggreg`

``````for (Item item: Items) {
List &lt; Tax &gt; taxes = item.getTaxes;
for (Tax tax: taxes) {
createTax(Tax tax);
}
}

private void createTax(Tax tax) {
if (!taxAggreg.isEmpty() &amp;&amp; taxAggreg.containsKey(tax.getTaxId())) {
Aggregate aggreg = taxAggreg.get(tax.getTaxId());
taxAggreg.put(tax.getTaxId(), aggreg);
} else {
taxAggreg.put(tax.getTaxId(), new Aggregate(tax.getTaxId(), tax.getName(),
tax.getTaxAmount()));
}
}
``````

# 答案1

``````Map<Integer, Aggregate> resMap = items.stream()
.flatMap(item -> item.getTaxes().stream())
.map(tax -> new Aggregate(tax.getTaxId(), tax.getName(), tax.getTaxAmount()))
.collect(Collectors.toMap(Tax::getTaxId, e -> e,
(a, b) -> new Aggregate(a.getTaxId(), a.getName(),
``````

``````Collectors.toMap(Tax::getTaxId, e -> e,
(a, b) -> new Aggregate(a.getTaxId(), a.getName(),
``````

First, flat the list of tag for item, then transform the Tax object into Aggregate object. Then map by tax id using `Collectors.toMap` then merge tax objects with same id.

``````Map&lt;Integer, Aggregate&gt; resMap = items.stream()
.flatMap(item -&gt; item.getTaxes().stream())
.map(tax -&gt; new Aggregate(tax.getTaxId(), tax.getName(), tax.getTaxAmount()))
.collect(Collectors.toMap(Tax::getTaxId, e -&gt; e,
(a, b) -&gt; new Aggregate(a.getTaxId(), a.getName(),
``````

Here using `Collectors.toMap` map by `Tax::getTaxId` which is the first parameter of toMap. The next one is the key of the map `e -&gt; e` for the whole `Aggregate` obj as key. And finally, the last parameter in the merge function will be used for merging two `Aggregate` objects into one `Aggregate` object so that all values of the same key merged into one `Aggregate` object

``````Collectors.toMap(Tax::getTaxId, e -&gt; e,
(a, b) -&gt; new Aggregate(a.getTaxId(), a.getName(),
``````

# 答案2

``````List<Aggregate> list1 = new ArrayList<Aggregate>();
List<Aggregate> list2 = new ArrayList<Aggregate>();

// 将数据添加到列表中...

// 现在为列表中每个对象创建带有其标识的映射
Map<String, Aggregate> aggregateMap1 = list1.stream().collect(Collectors.toMap(Aggregate::getId, Function.identity()));
Map<String, Aggregate> aggregateMap2 = list2.stream().collect(Collectors.toMap(Aggregate::getId, Function.identity()));

// 现在合并列表并将金额相加
List<Aggregate> result = aggregateMap1.keySet().stream().map(key -> {
Aggregate aggr1 = aggregateMap1.get(key);
Aggregate aggr2 = aggregateMap2.get(key);
if (aggr2 != null) {
aggr1.setAmount(aggr1.getAmount() + aggr2.getAmount());
}
return aggr1;
}).collect(Collectors.toList());
``````

Maybe something like this could work:

``````    List&lt;Aggregate&gt; list1 = new ArrayList&lt;Aggregate&gt;();
List&lt;Aggregate&gt; list2 = new ArrayList&lt;Aggregate&gt;();

// Now create maps with the identity for each object in lists
Map&lt;String, Aggregate&gt; aggregateMap1 = list1.stream().collect(Collectors.toMap(Aggregate::getId, Function.identity()));
Map&lt;String, Aggregate&gt; aggregateMap2 = list2.stream().collect(Collectors.toMap(Aggregate::geId, Function.identity()));

// Now merge lists and add the amounts together
List&lt;Aggregate&gt; result = aggregateMap1.keySet().forEach(key -&gt; aggregateMap1.merge(key,
aggregateMap2.get(key),
(aggr1, aggr2) -&gt; {
aggr1.setAmount(aggr1.getAmount() + aggr2.getAmount());
return aggr1;
})).values().stream().collect(Collectors.toList());;
``````

Not tested. Also could be fine tuned.

• 本文由 发表于 2020年7月30日 20:01:30
• 转载请务必保留本文链接：https://go.coder-hub.com/63172738.html
• java
• java-8

go 82

go 88

go 50

go 49