如何将具有列表中相同值的两个字段的对象组合到一个简化列表中?

Don*_*mmy 1 java java-8

我有这个类的对象列表:

class Item
{
    private String name;
    private String parentName;
    private Integer someValue;
    private Double anotherValue;

    public Item() {}

    //...elided getters/setters...
}
Run Code Online (Sandbox Code Playgroud)

我有一个列表,其中包含以下值:

//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
    }
];
Run Code Online (Sandbox Code Playgroud)

我希望将其合并到此列表中:

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
    }
];
Run Code Online (Sandbox Code Playgroud)

基本上规则是:

  • 如果name和parentName在两个对象中都相同:
    • 将它们组合成一个对象
    • 求和"someValue"字段
    • 求和"anotherValue"字段
  • 如果name或parentName之一是diff,请不要合并

我将如何在Java 8流中执行此操作?

我开始将它们放入桶中(见下文),但我不确定从哪里开始:

items
    .stream()
    .collect(
        Collectors.groupingBy(
            item -> new ArrayList<String>( Arrays.asList( item.getName(), item.getParentName() ) ) 
        )
    );
Run Code Online (Sandbox Code Playgroud)

小智 5

collect(groupingBy())方法返回一个地图.

如果您定义以下类:

class Tuple {
    String name;
    String parentName;
}
Run Code Online (Sandbox Code Playgroud)

那么你可以获得以下地图:

Map<Tuple, List<Item>> groupedItems = items.stream().collect(
            groupingBy(item -> new Tuple(item.getName(), item.getParentName())));
Run Code Online (Sandbox Code Playgroud)

现在你可以这样操作:

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());
Run Code Online (Sandbox Code Playgroud)