3

How to filter dynamically nested list object java 8

Example:

class Items {
    List<Mobile> mobiles;
}

class Mobile{
    String mName;
    List<Plans> plans;
}

class Plans{
    String planId;
    String planName;
}

So, I have 3 mobiles (mobiles will be dynamic 3 or 4..etc) with multiple plans on each mobile device. How to dynamically filter common plan for each mobile device ?

Example(P1-planId) :
Items:
    M1 - P1,P2,P3,P4
    M2 - P4,P5,P6,P1,P8,P2
    M3 - P7,P2,P4,P1,P8,P9,P10
Result:
Items:
    M1 - P1,P2,P4
    M2 - P1,P2,P4
    M3 - P1,P2,P4
3
  • You can start iterating with the first mobile and store all its plan to a list. Then while iterating on other mobiles from your input, retainAll those plans which are also a part of the current mobile you are iterating in the loop. You would be left only with plans common to all at the end. Commented Aug 8, 2020 at 5:21
  • Is there a reason why P4 isn't in the result set? Commented Aug 8, 2020 at 5:33
  • P4 also to be added M1 - P1,P2,P4 M2 - P1,P2,P4 M3 - P1,P2,P4 Commented Aug 8, 2020 at 5:51

3 Answers 3

2

A method inside Items to get all plans common to all mobiles might look like:

public List<Plan> getCommonPlans() {
    return mobiles.stream().flatMap(Mobile::streamPlans).distinct()
        .filter(p -> mobiles.stream().allMatch(m -> m.hasPlan(p)))
        .collect(Collectors.toList());
}

this assumes Mobile.streamPlans and Mobile.hasPlan methods which are pretty trivial.

A slightly different method, more efficient but perhaps not so intuitive, is to count the plans and filter for ones that have counts equal to number of mobiles:

    return mobiles.stream().flatMap(Mobile::streamPlans)
        .collect(Collectors.groupingBy(m -> m, Collectors.counting())
        .entrySet().stream()
        .filter(e -> e.getValue() == mobiles.size())
        .map(Map.Entry::getKey)
        .collect(Collectors.toList());
Sign up to request clarification or add additional context in comments.

Comments

1

First, take plans of the first mobile and retainAll plans of mobiles from that list.

List<Plans> commonPlans = new ArrayList<>(mobiles.get(0).getPlans());
for (int i = 1; i < mobiles.size(); i++) {
  commonPlans.retainAll(mobiles.get(i).getPlans());
}

Note: Make sure you override equals and hashCode for Plans and check for empty mobiles list

Comments

0

A slightly different approach would be to:

  • stream all Mobiles,
  • map each Mobile to its List<Plan>s
  • create the union of all plans.

In code, this might look something like this:

HashSet<Plan> initialSet = new HashSet<>(mobiles.get(0).getPlans());
return mobiles.stream()
    .map(Mobile::getPlans)
    .map(HashSet<Plan>::new)
    .reduce(initialSet, (plan1, plan2) -> { 
        plan1.retainAll(plan2);
        return plan1;
    });

Ideone demo

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.