我有一个类似于以下的课程。
public class Votes{
String name;
int likes;
int dislikes;
//constructors, getters and setters
}
我有一个如下列表。
List<Votes> votesList;
假设我在列表中填充了一些元素。我想声明一个在该列表中执行分组和求和操作的方法。
作为示例,假设我在列表中提供以下元素作为该方法的input
。
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));
该方法应输出带有以下元素的List<Votes>
。
("A", 30, 20),
("B", 25, 35),
("C", 10, 35)
在Java8中使用stream,lambda表达式是否有一种简单的方法可以做到这一点?我知道如果我只有一个collectors
成员,可以使用int
来完成。
有人可以解释一下我该如何处理这种情况?
答案 0 :(得分:3)
一种方法是使用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
拷贝构造函数(使用collectingAndThen
和m -> new ArrayList<>(m.values())
,或者将前一个表达式放在这个拷贝构造函数的参数列表中。) / p>
答案 1 :(得分:3)
最后,我认为这是最简单的方法。 :))
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 :(得分:2)
这应该让你开始,它不是你想要的,因为它不会创建最终列表。
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());
});
答案 3 :(得分:2)
这是使用自定义收集器的解决方案。
测试代码:
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类:
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();
}
}
输出
A 30 20
B 25 35
C 10 35
Here是学习编写收藏家的众多好来源之一: