如何在Java 8中动态过滤嵌套的列表对象

3
如何在Java 8中动态过滤嵌套列表对象
示例:
class Items {
    List<Mobile> mobiles;
}

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

class Plans{
    String planId;
    String planName;
}

我有3个手机(手机数量可能会动态变化,例如3个或4个等),每个手机设备上都有多个计划。如何动态过滤出每个手机设备的共同计划?

Items:
    M1 - P1,P2,P3,P4
    M2 - P4,P5,P6,P1,P8,P2
    M3 - P7,P2,P4,P1,P8,P9,P10

Items:
    M1 - P1,P2,P4
    M2 - P1,P2,P4
    M3 - P1,P2,P4

你可以从第一个手机开始迭代,并将其所有计划存储到列表中。然后在迭代输入的其他手机时,使用 retainAll 保留那些也是当前正在循环迭代的手机的一部分的计划。最终,你将只剩下所有手机共有的计划。 - Naman
P4没有出现在结果集中,有什么原因吗? - Don Foumare
P4也要加入 M1 - P1,P2,P4 M2 - P1,P2,P4 M3 - P1,P2,P4 - java32776
3个回答

2

Items中用于获取所有手机通用计划的方法可能如下:

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

这假设了Mobile.streamPlansMobile.hasPlan方法,这些方法相当简单。
另一种略微不同但更有效的方法是计算计划数量并过滤出具有与移动设备数量相等计数的计划:
    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());

1
首先,获取第一部手机的计划以及从该列表中保留所有手机的计划。
List<Plans> commonPlans = new ArrayList<>(mobiles.get(0).getPlans());
for (int i = 1; i < mobiles.size(); i++) {
  commonPlans.retainAll(mobiles.get(i).getPlans());
}

注意:请确保为Plans覆盖equalshashCode方法,并检查移动列表是否为空。


0

一个稍微不同的方法是:

  • 流式处理所有Mobile
  • 将每个Mobile映射到其List<Plan>
  • 创建所有计划的联合。

代码如下:

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演示


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接