Atum
Atum

Reputation: 1301

java 8 stream how to groupingBy in result groupingBy?

how to find max LawInfo by date fo all games in groupingBy LawInfoType?

i have simple model :

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

main test

 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)); //!!!????

but I need to get in each group max by date group by games

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

small->[LawInfo(football, max date),LawInfo(hokey, max date) ,LawInfo(golf, max date) , LawInfo(basketball, max date)]

middle->[LawInfo(football, max date),LawInfo(hokey, max date) ,LawInfo(golf, max date) , LawInfo(basketball, max date)]

big->[LawInfo(football, max date),LawInfo(hokey, max date) ,LawInfo(golf, max date) , LawInfo(basketball, max date)]

Upvotes: 1

Views: 4669

Answers (2)

Holger
Holger

Reputation: 298123

You can use

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

which will print

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

with your test data. Note that date values in that range are not quite suitable for consistency checks as other dates of this data set may look like having a higher number in printouts because the year is not printed as signed number with this format. I’d recommend to generate dates with reasonable values, e.g. having four digit positive number years…

Upvotes: 3

k5_
k5_

Reputation: 5558

You could group by two properties (getTextType and getGame), and a max collector.

Something like this:

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

Upvotes: 1

Related Questions