在Java8中使用groupingBy和summingInt扩展流的输出

地热

我有一个主题:

@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方法获取给定日期的主题列表:

列出主题= 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)

我尝试达到的结果是将结果输出过滤为(如果日期&&用户是相同的添加点)

Topic(id=1, date="2018-01-01", name="Java examples", User(...), 12)
Topic(id=2, date="2018-02-02", name="Java examples", User(...), 90)
Topic(id=4, date="2018-03-03", name="Java examples", User(...), 168)

我的实际解决方案返回以日期为键,以总和点为值的map,但是我需要在输出中提供更多数据,例如User或name。

return topics.stream()
        .collect(Collectors.groupingBy(Topic::getDate,
                Collectors.summingInt(Topic::getPoints)));

也许有另一种方法可以代替dto为这种情况创建的dto吗?例如

@Data
public class ResultDto {
    private LocalDate date;
    private String name;
    private int points;
    private User user;
}
帧/秒

假设User实现hashCodeequals 始终如一,您可以将其分组为日期/用户复合键和ResultDto的映射为此,您需要执行两项操作:一项用于映射to,另一项用于汇总每个组的点。(您可以将这些操作放置ResultDto在实用程序类或在实用程序类中,在这里,我假设第一个操作在Mapper实用程序类中,第二个在实用程序类中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;
    }
}

ResultDto

public ResultDto merge(ResultDto another) {
    this.points += another.points;
    return this;
}

请注意,我要分配Topic.nameMapper.fromTopic映射操作中找到的第一个我假设这是您的示例中的不一致之处,如果您在现实世界中使用此方法,请考虑到这一点。

现在,我们可以流播主题并按日期/用户分组:

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

这收集到一个键为a的地图,List其第一个元素为日期,第二个元素为用户。这些2元素列表对于以后的使用不是很有用,这里我们仅使用它们来创建复合键并通过该键对主题进行分组。映射的值是一个ResultDto实例,实例最初是从主题创建的,然后与属于同一组(相同日期和用户)的其他主题合并。在此ResultDto.merge操作中,points将求和。

您需要的结果是地图的值:

Collection<ResultDto> results = groups.values(); // or new ArrayList<>(groups.values())

编辑:这是一个没有流的更为简洁的变体:

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章