如何合并类似对象的列表,但总结一些属性与Java 8

Ade*_*lin 6 java java-8 java-stream

假设我有下面的列表我想返回一个只有一个名字的人的结果"Sam"- "Fred"但是有25金额

public class Java8Test{


    private static class Person {
            private String name;
            private String lastName;
            private int amount;

            public Person(String name, String lastName, int amount) {
                this.name = name;
                this.lastName = lastName;
                this.amount = amount;
            }
        }


        public static void main(String[] args) {
            List<Person> people = new ArrayList<>();
            people.add(new Person("Sam","Fred",10));
            people.add(new Person("Sam","Fred",15));
            people.add(new Person("Jack","Eddie",10));
            // WHAT TO DO HERE ?


        }
    }
Run Code Online (Sandbox Code Playgroud)

注意:

上面的例子只是为了澄清,我正在寻找的是使用Java 8的通用映射/减少功能.

azr*_*zro 5

您可以使用groupingBy,reducing和其他东西来: - 按相同的名字和姓氏对人员进行分组 - 将其金额的值相加 - 创建具有这些属性的人员

people = people.stream().collect(
                         Collectors.groupingBy(o -> Arrays.asList(o.name, o.lastName), 
                               Collectors.summingInt(p->p.amount))
            .entrySet()
            .stream()
            .map(Person::apply).collect(Collectors.toList());

people.forEach(System.out::println);

//Prints : 
Sam Fred 25
Jack Eddie 10
Run Code Online (Sandbox Code Playgroud)

这两个是相同的(我的 IDE 向我建议,我假设我真的不知道它是如何工作的,如果有人知道:在评论中向我们解释)

.map(Person::apply) 
.map(e -> new Person(e.getKey().get(0), e.getKey().get(1), e.getValue())
Run Code Online (Sandbox Code Playgroud)

  • `人::申请`? (4认同)
  • `Collectors.summingInt(Person::getAmount)` 可能比 `Collectors.reducing(0, Person::getAmount, Integer::sum)` 更有效(甚至更短)...... `.map(Person::apply) ` 需要在类 `Person` 中有一个未指定的 `static` `apply` 方法。你可能指的是`.map(e -&gt; new Person(e.getKey().get(0), e.getKey().get(1), e.getValue())` (4认同)

Fed*_*ner 5

您可以迭代people列表并使用地图合并具有相同name - lastName对的人:

Map<String, Person> map = new HashMap<>();
people.forEach(p -> map.merge(
    p.getName() + " - " + p.getLastName(),                  // name - lastName
    new Person(p.getName(), p.getLastName, p.getAmount()),  // copy the person
    (o, n) -> o.setAmount(o.getAmount() + n.getAmount()))); // o=old, n=new
Run Code Online (Sandbox Code Playgroud)

现在map.values()减少 Collection<Person>按您的要求.

如果你有可能在类中添加一个拷贝构造函数和几个方法Person:

public Person(Person another) {
    this.name = another.name;
    this.lastName = another.lastName;
    this.amount = another.amount;
}

public String getFullName() {
    return this.name + " - " + this.lastName;
}

public Person merge(Person another) {
    this.amount += another.amount;
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以简化代码的第一个版本,如下所示:

Map<String, Person> map = new HashMap<>();
people.forEach(p -> map.merge(p.getFullName(), new Person(p), Person::merge));
Run Code Online (Sandbox Code Playgroud)

这利用了这种Map.merge方法,这对这种情况非常有用.


Ale*_*amo 0

你的Person类应该是这样的:

private static class Person {
    private String name;
    private String lastName;
    private int amount;

    public Person(String name, String lastName, int amount) {
        this.name = name;
        this.lastName = lastName;
        this.amount = amount;
    }

    public String getName() {return name;}
    public String getLastName() {return lastName;}
    public int getAmount() {return amount;}
    public String toString() {
        return name + " / " + lastName + " / " + String.valueOf(amount);
    }
}
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,我已经为你的文件添加了公共吸气剂。要实现您想要的,请使用以下代码:

Person person = people.stream()
    .filter(p -> p.getName().equals("Sam"))
    .filter(p -> p.getLastName().equals("Fred"))
    .reduce(new Person("Sam","Fred",0), (p1, p2) -> {
         p1.amount += p2.amount;
    return new Person("Sam","Fred", p1.amount);
});
people.add(person);

Person p = people.stream()
    .reduce((p1, p2) -> p1.amount > p2.amount ? p1 : p2).get();
Run Code Online (Sandbox Code Playgroud)

结果是一个数量为 25 的单人对象。