java 8 stream如何在结果分组中进行分组?

时间:2016-07-07 11:01:55

标签: java lambda java-8 java-stream

如何在groupingBy LawInfoType中找到所有游戏的日期最大LawInfo?

我有简单的模型:

public enum Game {
    football,
    hokey,
    golf,
    basketball
}

public class LawInfo {
    private Date minDate;
    private State state;
    private LawInfoType textType;
    private String lawInfoText;
    private Game game;
}

public enum LawInfoType {
     big, middle , small;
}

public enum State {
    draft, ready, cancel;
}

主要测试

 List<LawInfo> list = new ArrayList<>();

        LawInfo info = null;
        Random random = new Random(123);
        for (int i = 0; i < 3; i++) {

            for (State state : State.values()) {
                for (LawInfoType lawInfoType : LawInfoType.values()) {
                    for (Game game : Game.values()) {
                        info = new LawInfo(new Date(random.nextLong()), state, lawInfoType, "TEXT", game);
                        list.add(info);
                    }

                }
            }
        }

        Predicate<LawInfo>  isReady = l->l.getState().equals(State.ready);


  Map<LawInfoType, List<LawInfo>> map0 = list.stream()
                .filter(isReady)
                .collect(groupingBy(LawInfo::getTextType)); //!!!????

但是我需要按照游戏日期分组加入每个组

like this : Map<LawInfoType, List<LawInfo>> 

small-&gt; [LawInfo(足球,最长日期),LawInfo(hokey,最大日期),LawInfo(高尔夫,最长日期),LawInfo(篮球,最长日期)]

middle-&gt; [LawInfo(足球,最长日期),LawInfo(hokey,最大日期),LawInfo(高尔夫,最长日期),LawInfo(篮球,最长日期)]

big-&gt; [LawInfo(足球,最大日期),LawInfo(hokey,最大日期),LawInfo(高尔夫,最长日期),LawInfo(篮球,最长日期)]

2 个答案:

答案 0 :(得分:3)

您可以使用

Map<LawInfoType, List<LawInfo>> result = list.stream()
    .filter(l -> l.getState()==State.ready)
    .collect(
        Collectors.groupingBy(LawInfo::getTextType,
            Collectors.collectingAndThen(
                Collectors.groupingBy(LawInfo::getGame,
                    Collectors.maxBy(Comparator.comparing(LawInfo::getMinDate))),
                m -> m.values().stream().map(Optional::get).collect(Collectors.toList())
        )));

result.forEach((k,v) -> {
    System.out.println(k);
    v.forEach(l -> System.out.printf("%14s, %15tF%n", l.getGame(), l.getMinDate()));
});

将打印

big
          golf, 250345012-06-20
    basketball,  53051589-05-19
      football, 177220545-11-30
         hokey, 277009605-05-01
middle
          golf,  24379695-11-03
    basketball, 283700233-08-25
      football, 248125707-04-08
         hokey, 195919793-04-22
small
          golf, 152237339-07-10
    basketball, 269880024-08-24
      football, 285393288-11-14
         hokey, 276036745-09-23

包含您的测试数据。请注意,该范围内的日期值不太适合一致性检查,因为此数据集的其他日期可能看起来就像在打印输出中具有更高的数字一样,因为年份不会以此格式打印为带符号的数字。我建议生成具有合理值的日期,例如有四位数的正数年......

答案 1 :(得分:1)

您可以按两个属性(getTextType和getGame)和最大收集器进行分组。

这样的事情:

Map<LawInfoType, Map<Game, Optional<LawInfo>>> map0 = list.stream().collect(
    Collectors.groupingBy(LawInfo::getTextType,
         Collectors.groupingBy(LawInfo::getGame,           
              Collectors.maxBy(Comparator.comparing(LawInfo::getMinDate))
    )));