How to combine a list of similar objects, but summarize some properties with Java 8

Suppose I have a list below. I would like to return a result that has only one Person named "Sam"- "Fred"but with 25amount

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 ?


        }
    }

NOTE.

The above example is for clarification only, I'm looking for a common map / reduce as functionality with Java 8.

+6
source share
7 answers

You can iterate your list peopleand use the map to join people with the same pair 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

Now map.values()is reduced Collection<Person>to suit your requirements.

- 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;
}

:

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

Map.merge, .

+5

groupingBy, reducing : - lastName - -

 
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

( IDE , , , , - : )

.map(Person::apply) 
.map(e -> new Person(e.getKey().get(0), e.getKey().get(1), e.getValue())
+4

, Stream, Collectors.groupingby .., Java 8 lambdas:

Map<List<String>, Person> persons = new LinkedHashMap<>();
for (Person p : people) {
    persons.compute(Arrays.asList(p.getName(), p.getLastName()),
            (s, p2) -> p2 == null ? p : new Person(p.getName(), p.getLastName(), p.getAmount() + p2.getAmount()));
}

- Map, "" .

{[Sam, Fred]=Person(name=Sam, lastName=Fred, amount=25),
 [Jack, Eddie]=Person(name=Jack, lastName=Eddie, amount=10)}
+3

:

TreeSet<Person> res = people.stream()
       .collect(Collector.of(
                    () -> new TreeSet<>(Comparator.comparing(Person::getName)
                                        .thenComparing(Person::getLastName)),
                    (set, elem) -> {
                        if (!set.contains(elem)) {
                            set.add(elem);
                        } else {
                            Person p = set.ceiling(elem);
                            p.setAmount(elem.getAmount() + p.getAmount());
                        }
                    },
                    (left, right) -> {
                        throw new IllegalArgumentException("not for parallel");
                    }));

Person . a Set, ( firstname lastname), , .

+3

groupingBy :

Function<Person, List<Object>> key = p -> Arrays.asList(p.name, p.lastName);
final Map<List<Object>, Integer> collect = people.stream()
    .collect(Collectors.groupingBy(key, Collectors.summingInt(p -> p.amount)));
System.out.println(collect);

{[Sam, Fred]=25, [Jack, Eddie]=10}

Person .

+3

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);
    }
}

, . , :

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();

25.

0

Collectors.toMap

private static class Person {
    String getName() {   return name; }

    String getLastName() {  return lastName;}

    int getAmount() {  return amount; }

    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));

    people.stream()
            .collect(Collectors.toMap(
                    person -> Arrays.asList(person.getName(), person.getLastName()),
                    Person::getAmount,
                    Integer::sum)
            )
            .forEach((key, value) -> System.out.println(key + " " + value));
}
0
source

All Articles