Reputation: 25860
I have a list of objects of this class:
class Item
{
private String name;
private String parentName;
private Integer someValue;
private Double anotherValue;
public Item() {}
//...elided getters/setters...
}
I have a list of these with the values:
//PSEUDO CODE (Not JavaScript, but using JSON is easier to follow)
List<Item> items = [
{
"name": "Joe",
"parentName": "Frank",
"someValue": 10,
"anotherValue": 15.0
},
{
"name": "Joe",
"parentName": "Frank",
"someValue": 40,
"anotherValue": 0.5
},
{
"name": "Joe",
"parentName": "Jack",
"someValue": 10,
"anotherValue": 10.0
},
{
"name": "Jeff",
"parentName": "Frank",
"someValue": 10,
"anotherValue": 10.0
}
];
I want this to be combined into this list:
List<Item> items = [
{
"name": "Joe",
"parentName": "Frank",
"someValue": 50,
"anotherValue": 15.5
},
{
"name": "Joe",
"parentName": "Jack",
"someValue": 10,
"anotherValue": 10.0
},
{
"name": "Jeff",
"parentName": "Frank",
"someValue": 10,
"anotherValue": 10.0
}
];
Basically the rules are:
How would I do this in Java 8 streams?
I started with putting them into buckets (see below) but am not sure where to go from here:
items
.stream()
.collect(
Collectors.groupingBy(
item -> new ArrayList<String>( Arrays.asList( item.getName(), item.getParentName() ) )
)
);
Upvotes: 1
Views: 1426
Reputation: 490
The collect(groupingBy())
method returns a map.
If you define the following class:
class Tuple {
String name;
String parentName;
}
then you can obtain the following map:
Map<Tuple, List<Item>> groupedItems = items.stream().collect(
groupingBy(item -> new Tuple(item.getName(), item.getParentName())));
Now you can operate on it like this:
List<Item> finalItems = groupedItems.entrySet().stream().map(entry ->
new Item(entry.getKey().name,
entry.getKey().parentName,
entry.getValue().stream().mapToInt(
item -> item.someValue).sum(),
entry.getValue().stream().mapToDouble(
item -> item.anotherValue).sum()))
.collect(Collectors.toList());
Upvotes: 5
Reputation: 5652
Here is a solution that uses some Java8 constructs (although its essentially a loop through the List, storing Items in a Map temporarily). :
List<Item> items;
Map<String, Item> masterItems;
items.forEach(item -> {
if (masterItems.containsKey(item.getName() + item.getParent())) {
Item matchedItem = masterItems.get(item.getName() + item.getParent());
matchedItem.setSomeValue(matchedItem.getSomeValue() + item.getSomeValue());
matchedItem.setOtherValue(matchedItem.getOtherValue() + item.getOtherValue());
} else {
masterItems.put(item.getName() + item.getParent(), item);
}
});
items.clear();
items.addAll(masterItems.values());
It could probably be refined to use more Java8 constructs... I'll have a go and see what I can do
Upvotes: 1