Using lambda expressions to add member variables?

I have a class like the following.

public class Votes{
    String name;
    int likes;
    int dislikes;

    //constructors, getters and setters    
}

I have a list like the following.

List<Votes> votesList;

Suppose I fill in some elements above the list. I want to declare a method that performs the grouping and summation operation on this list.

As an example, suppose I list the following items in a list as inputfor this method.

votesList.add(new Votes("A", 10, 5));
votesList.add(new Votes("B", 15, 10));
votesList.add(new Votes("A", 20, 15));
votesList.add(new Votes("B", 10, 25));
votesList.add(new Votes("C", 10, 20));
votesList.add(new Votes("C", 0, 15));

This method should output List<Votes>with the following elements.

("A", 30, 20),
("B", 25, 35),
("C", 10, 35)

Is there an easy way to do this using streams, lambda expressions in Java8? I know how this can be done using collectorsif I have only one intmemeber.

Can someone please explain to me how I can address this situation?

+4
4

, .:))

Map<String, List<Votes>> grouped = voteCountList.stream().collect(Collectors.groupingBy(r->r.getName()));

List<Votes> collectedList = new ArrayList<>();

grouped.forEach((groupName, votes) -> collectedList.add(new Votes(groupName,
                votes.stream().collect(Collectors.summingInt(r->r.getLikes())),
                votes.stream().collect(Collectors.summingInt(r->r.getDislikes())))));
+2

groupingBy, reducing:

Collection<Optional<Votes>> res =
     votesList.stream().collect(groupingBy(v -> v.name, reducing((v1, v2) -> new Votes(v1.name, v1.likes + v2.likes, v1.dislikes + v2.dislikes)))).values();

Collection<Optional<Votes>>, , reducing Optional::get collectingAndThen, .

, toMap, , :

Collection<Votes> res =
    votesList.stream().collect(toMap(v -> v.name,
                                     v -> v,
                                     (v1, v2) -> new Votes(v1.name, v1.likes + v2.likes, v1.dislikes + v2.dislikes))).values();

ArrayList copy-constructor ( collectingAndThen m -> new ArrayList<>(m.values()), ).

+3

This should get you started, this is not exactly what you want, as it does not create the final list.

Map<String, Votes> collected = votesList.stream().collect(Collectors.groupingBy(Votes::getName,
        collectingAndThen(reducing(
                (originalVotes, newVotes) -> new Votes(originalVotes.getName(), originalVotes.getLikes() + newVotes.getLikes(), originalVotes.getDislikes() + newVotes.getDislikes()))
                , Optional::get)));

collected.forEach((key, value) -> {
    System.out.println(key + "," + value.getLikes() + "," + value.getDislikes());
});
+2
source

Here's a solution using a custom collector.

Test code:

final List<Votes> votesList = new ArrayList<>();
votesList.add(new Votes("A", 10, 5));
votesList.add(new Votes("B", 15, 10));
votesList.add(new Votes("A", 20, 15));
votesList.add(new Votes("B", 10, 25));
votesList.add(new Votes("C", 10, 20));
votesList.add(new Votes("C", 0, 15));

final List<Votes> totals = votesList.stream().collect(new VoteCollector());
totals.forEach(votes -> {
    System.out.println(votes.getName() + "  " + votes.getLikes() + "  " + votes.getDislikes());
});

VoteCollector Class:

import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;

public class VoteCollector implements Collector<Votes, Map<String, Votes>, List<Votes>> {

    @Override
    public Supplier<Map<String, Votes>> supplier() {
        return HashMap::new;
    }

    @Override
    public BiConsumer<Map<String, Votes>, Votes> accumulator() {
        return (map, votes) -> {
            final Votes mapVotes = map.get(votes.getName());
            if (mapVotes == null) {
                map.put(votes.getName(), new Votes(votes.getName(), votes.getLikes(), votes.getDislikes()));
            } else {
                mapVotes.setLikes(mapVotes.getLikes() + votes.getLikes());
                mapVotes.setDislikes(mapVotes.getDislikes() + votes.getDislikes());
            }
        };
    }

    @Override
    public BinaryOperator<Map<String, Votes>> combiner() {
        return (map1, map2) -> {
            for (final Entry<String, Votes> map2Entry : map2.entrySet()) {
                final Votes map1Votes = map1.get(map2Entry.getKey());
                if (map1Votes == null) {
                    map1.put(map2Entry.getKey(), map2Entry.getValue());
                }
                else {
                    map1Votes.setLikes(map1Votes.getLikes() + map2Entry.getValue().getLikes());
                    map1Votes.setDislikes(map1Votes.getDislikes() + map2Entry.getValue().getDislikes());
                }
            }

            return map1;
        };
    }

    @Override
    public Function<Map<String, Votes>, List<Votes>> finisher() {
        return map -> map.values().stream().collect(Collectors.toList());
    }

    @Override
    public Set<Characteristics> characteristics() {
        return Collections.emptySet();
    }   
}

Output signal

A  30  20
B  25  35
C  10  35

Here is one of many good sources for educating collectors:

+2
source

Source: https://habr.com/ru/post/1657512/


All Articles