Java 8 使用groupingBy&;扩展流的输出;Java8中的summingit
我有一个话题:Java 8 使用groupingBy&;扩展流的输出;Java8中的summingit,java-8,java-stream,Java 8,Java Stream,我有一个话题: @Entity public class Topic { @Id private int id; private LocalDate date; private String name; private int points; @JoinColumn(name = "user_id", nullable = false) private User user; } 我通过spring data jpa方法获得给定日期内的主题
@Entity
public class Topic {
@Id
private int id;
private LocalDate date;
private String name;
private int points;
@JoinColumn(name = "user_id", nullable = false)
private User user;
}
我通过spring data jpa方法获得给定日期内的主题列表:
List topics=topicRepository.findByDateBetween(开始,结束);
在输出上有哪些功能,例如:
Topic(id=1, date="2018-01-01", name="Java examples", User(...), 12)
Topic(id=2, date="2018-02-02", name="Java examples", User(...), 34)
Topic(id=3, date="2018-02-02", name="Java examples", User(...), 56)
Topic(id=4, date="2018-03-03", name="Java examples", User(...), 78)
Topic(id=5, date="2018-03-03", name="Java examples", User(...), 90)
我试图实现的是过滤我的结果输出(如果日期和用户是相同的添加点)
我的实际解决方案返回的映射以日期为键,汇总点为值,但我需要在输出中提供更多数据,如用户名或名称
return topics.stream()
.collect(Collectors.groupingBy(Topic::getDate,
Collectors.summingInt(Topic::getPoints)));
也许有另一种方法来代替映射返回为这种情况创建的dto?e、 g
@Data
public class ResultDto {
private LocalDate date;
private String name;
private int points;
private User user;
}
假设
User
一致地实现hashCode
和等于
,则可以将日期/用户组合键和ResultDto
值分组到映射。为此,您需要两个操作:一个是将映射到
,另一个是为每个组聚合点。(您可以将这些操作放在ResultDto
或实用程序类中,等等,这里我假设第一个操作在Mapper
实用程序类中,第二个操作在ResultDto
中):
在ResultDto
中:
public final class Mapper {
private Mapper() { }
public static ResultDto fromTopic(Topic topic) {
ResultDto result = new ResultDto();
result.setDate(topic.getDate());
result.setName(topic.getName());
result.setPoints(topic.getPoints());
result.setUser(topic.getUser());
return result;
}
}
public ResultDto merge(ResultDto another) {
this.points += another.points;
return this;
}
请注意,我正在分配Mapper.fromTopic
映射操作中找到的第一个Topic.name
。我假设这在您的示例中是不一致的,如果您在实际场景中使用此方法,请将其考虑在内
现在,我们可以按日期/用户对主题和组进行流式处理:
Map<List<Object>, ResultDto> groups = topics.stream()
.collect(Collectors.toMap(
topic -> Arrays.asList(topic.getDate, topic.getUser()), // Java 9: List.of
Mapper::fromTopic,
ResultDto::merge));
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.summingInt;
Comparator<Topic> byDateAndUser = Comparator.comparing(Topic::getDate)
.thenComparing(t -> t.getUser().getUserId());
Map<Topic, Integer> pointTotals = topics.stream()
.collect(groupingBy(
topic -> topic,
() -> new TreeMap<>(byDateAndUser),
summingInt(Topic::getPoints)
));
编辑:这里有一个没有流的更简洁的变体:
Map<List<Object>, ResultDto> groups = new HashMap<>();
topics.forEach(topic -> groups.merge(
List.of(topic.getDate(), topic.getUser()), // Java 8: Arrays.asList
Mapper.fromTopic(topic),
ResultDto::merge));
Collection<ResultDto> results = groups.values();
Map groups=newhashmap();
topics.forEach(topic->groups.merge(
List.of(topic.getDate(),topic.getUser()),//Java 8:Arrays.asList
Mapper.fromTopic(主题),
结果:合并);
收集结果=groups.values();
按字段子集进行分组的一种简单方法是使用带有自定义比较器的树形图。假设你要定义
Comparator<Topic> byDateAndUser = Comparator.comparing(Topic::getDate)
.thenComparing(t -> t.getUser().getUserId());
Map<Topic,...> map = new TreeMap<>(byDateAndUser);
用户是否也需要相同?我的意思是,您是否需要按日期和用户分组,即如果对于2018-02-02
您有2个用户,user 1
有10和5,user 2
有20和8,您将有两个组,(2018-02-02,user 1)
有15和(2018-02-02,user 2)
有28?是的,我给出了一个例子,当用户是相同的时候会发生什么。但你是对的,这就像你写的。好吧,那名字呢?你也需要按那个分组吗?如果不是,它不应该是ResultDto
的属性(或者此dto应该有一个组成该组的所有名称的列表)。您的权利。不应该。但我们可以假设,我们也需要这个。谢谢@Federico。不幸的是,我需要离开。我会核对答案并尽快接受(可能明天早上)。再次感谢,祝你今天愉快。
Comparator<Topic> byDateAndUser = Comparator.comparing(Topic::getDate)
.thenComparing(t -> t.getUser().getUserId());
Map<Topic,...> map = new TreeMap<>(byDateAndUser);
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.summingInt;
Comparator<Topic> byDateAndUser = Comparator.comparing(Topic::getDate)
.thenComparing(t -> t.getUser().getUserId());
Map<Topic, Integer> pointTotals = topics.stream()
.collect(groupingBy(
topic -> topic,
() -> new TreeMap<>(byDateAndUser),
summingInt(Topic::getPoints)
));