3

I have a list

PLANS:

ID,    A_CODE, COMPARTMENT
10683   163     213 
10683   616     194
10683   163     212
10683   163     211
10683   163     214

and want to produce AGGREGATED_PLANS

ID      A_CODE  COMPARTMENTS
10683   163     211/212/213/214
10683   616     194

How can I do this using java lambda expression ?

I am thinking something like this, but not sure about the aggregateCompartments part ?

plans.stream()
     .collect(groupingBy(Plan::getACode, 
           aggregateCompartments(Plan::getCompartments)));

Any suggestions ?

2
  • 2
    Please update your question with a minimal, complete, and verifiable example. Commented Feb 15, 2018 at 5:47
  • Does using groupingBy(Plan::getACode, mapping(Plan::getCompartments, joining("/")), help? Commented Feb 15, 2018 at 5:53

3 Answers 3

1

this may help you:

    List<Plan> plans = new ArrayList<>();
    plans.add(new Plan("10683", "163", "213"));
    plans.add(new Plan("10683", "616", "194"));
    plans.add(new Plan("10683", "163", "212"));
    plans.add(new Plan("10683", "163", "211"));
    plans.add(new Plan("10683", "163", "214"));

    System.out.println(
        plans.stream().collect(
               Collectors.groupingBy(p -> p.id + " " + p.aCode, 
               Collectors.mapping(Plan::getCompartment, Collectors.joining("/")))));

output:

{10683 616=194, 10683 163=213/212/211/214}
Sign up to request clarification or add additional context in comments.

Comments

1

If I get you right, your desired output is a collection of plans, where compartment field of each plan is aggregated from all grouped compartments.

In this case I suggest you to use a toMap collector, which has a special mergeFunction argument:

Collection<Plan> aggregatedPlans = plans
    .stream()
    .collect(toMap(
            Plan::getACode,
            p -> new Plan(p.getId(), p.getACode(), p.getCompartment()),
            (p1, p2) -> {
                p1.compartment += "/" + p2.compartment;
                return p1;
            }))
    .values();

If you add the following two methods to your Plan object

public Plan clone() {
    return new Plan(id, aCode, compartment);
}

public Plan merge(Plan other) {
    compartment += "/" + other.compartment;
    return this;
}

then the code can be simplified like this:

Collection<Plan> aggregatedPlans = plans.stream()
            .collect(toMap(Plan::getACode, Plan::clone, Plan::merge)).values();

Comments

0

If you want to grupo by A_CODE:

Map<ACodeType, Set<CompartmentType>> result = plans.stream()
    .collect(Collectors.groupingBy(
        Plan::getACode, 
        Collectors.mapping(
            Plan::getCompartments, 
            Collectors.toCollection(TreeSet::new))));

This groups by A_CODE, with a downstream collector that first adapts each plan to its compartment and then collects each adapted group to a TreeSet, to maintain the compartments sorted and without duplicates. This needs the type of the compartment to be Comparable. If it's not, you'd need to provide a Comparator to the TreeSet's constructor.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.