Remo
Remo

Reputation: 604

groupingBy List of Object instead of Map

Having below class

class Train {
  String type;
  List<RateInfo> rateInfos;
}

want to groupBy type and needs to return as List

rateType will be AC, general, VIP

Here I am grouping by rateType.

Map<String, List<RateInfo>> collect 
    = rateInfos.stream()
               .collect(Collectors.groupingBy(RateInfo::getRateType));

Instead of collecting as Map<String, List<RateInfo>>, I want to collect it as List<Train>.

the List<Train> will have always 3 elements(based on rateType)

for example:

[rateType:"AC", roomTypeInfos: [n nmuber of values], rateType:"general", roomTypeInfos: [n nmuber of values], rateType:"economy", roomTypeInfos: [n nmuber of values]]

how to transform it?

Upvotes: 1

Views: 795

Answers (2)

Nowhere Man
Nowhere Man

Reputation: 19545

Class Train may be updated with a constructor accepting a RateInfo parameter. and a merge function needs to be implemented.

Also, merge function needs to be implemented to add appropriate RateInfo to the list in the current instance of Train.

@Data
@AllArgsConstructor
class Train {
    String type;
    List<RateInfo> rateInfos;

    public Train(RateInfo rate) {
        this(rate.rateType, new ArrayList<>());
        this.rateInfos.add(rate);
    }

    public Train merge(Train that) {
        this.rateInfos.addAll(that.rateInfos);
        return this;
    }
}

Then it could be convenient to use Collectors::collectingAndThen along with Collectors::toMap to build a map with rateType key, and convert to the List<Train>:

List<RateInfo> rateInfos = Arrays.asList(
        new RateInfo("AC", 200),
        new RateInfo("AC", 300),
        new RateInfo("General", 400),
        new RateInfo("General", 500),
        new RateInfo("General", 750),
        new RateInfo("VIP", 800),
        new RateInfo("VIP", 1000)
);

List<Train> merged = rateInfos.stream()
        .collect(Collectors.collectingAndThen(
                Collectors.toMap(RateInfo::getRateType, Train::new, Train::merge, LinkedHashMap::new), // Map<String, Train> created here
                map -> new ArrayList<>(map.values()) // from Collection<Train>
        ));

merged.forEach(System.out::println);

Output:

Train(type=AC, rateInfos=[RateInfo(rateType=AC, rate=200), RateInfo(rateType=AC, rate=300)])
Train(type=General, rateInfos=[RateInfo(rateType=General, rate=400), RateInfo(rateType=General, rate=500), RateInfo(rateType=General, rate=750)])
Train(type=VIP, rateInfos=[RateInfo(rateType=VIP, rate=800), RateInfo(rateType=VIP, rate=1000)])

Upvotes: 1

Gautham M
Gautham M

Reputation: 4935

I think each grouping is to be mapped into a Train object. Create a constructor for the Train class with type and the list passed as arguments. Then update your current code as:

// This generates a List<Train>
rateInfos.stream()
          .collect(Collectors.groupingBy(RateInfo::getRateType))
          .entrySet()
          .map(entry -> new Train(entry.getKey(), entry.getValue())
          .collect(Collectors.toList()); 

Upvotes: 1

Related Questions