单个流中的多个过滤器

时间:2016-05-30 01:47:15

标签: lambda java-8

我已经使用Java 8流编写了代码,但尝试重构。

我已使用不同的条件过滤列表并将其存储到新列表中。有没有办法一次过滤所有条件并将结果组存储到列表中。我不知道如何解释。

这是我的代码,只需要重构它。

List<A> finalList = new ArrayList<>();
List<A> aList= new ArrayList<>();

A objectA = new A();

List<B> bList = new ArrayList<>();
bList.add(new B(5700));
bList.add(new B(5750));
bList.add(new B(5800));
bList.add(new B(5812));
bList.add(new B(5803));
bList.add(new B(5802));

objectA.setMyList(bList);

aList.add(objectA);

aList.stream()
    .forEach(
        a -> {
            if(!a.getMyList.isEmpty()){
                List<B> groupA =
                    a.getMyList.stream()
                        .filter(b -> b.getType() == 5700 || b.getType() == 5750)
                        .collect(Collectors.toList());
                List<B> groupB =
                    a.getMyList.stream()
                        .filter(b -> b.getType() == 5800 || b.getType() == 5810)
                        .collect(Collectors.toList());
                List<B> groupC =
                    a.getMyList.stream()
                        .filter(b -> b.getType() == 5802 || b.getType() == 5812)
                        .collect(Collectors.toList());
                List<B> groupD =
                    a.getMyList.stream()
                        .filter(b -> b.getType() == 5803 || b.getType() == 5813)
                        .collect(Collectors.toList());



                if(!groupA.isEmpty()){
                    finalList.add(getAWithGroupList(a, groupA));
                }
                if(!groupB.isEmpty()){
                    finalList.add(getAWithGroupList(a, groupB));
                }
                if(!groupC.isEmpty()){
                    finalList.add(getAWithGroupList(a, groupC));
                }
                if(!groupD.isEmpty()){
                    finalList.add(getAWithGroupList(a, groupD));
                }
             }
        }
    );


private A getAWithGroupList(A a, List<B> group) {
    A a = (A) a.clone();
    a.setMyList(group);
    return a;
}

任何帮助或建议都将不胜感激。

感谢。

2 个答案:

答案 0 :(得分:1)

简单。用方法包装重复代码:

private List<B> listifyAndfilter(A a, Predicate<List<B>> check){
    return a.getMyList.stream().filter(check).collect(Collectors.toList());
}

然后你可以这样做:

List<B> groupA = listifyAndFilter(a, b -> b.getType() == 5700 || b.getType() == 5750),
        groupB = listifyAndFilter(a, b -> b.getType() == 5800 || b.getType() == 5810),
        groupC = listifyAndFilter(a, b -> b.getType() == 5802 || b.getType() == 5812),
        groupD = listifyAndFilter(a, b -> b.getType() == 5803 || b.getType() == 5813);

注意行末尾的逗号。

无关但有用:您还可以合并这些if语句:

if(!groupA.isEmpty()){
    finalList.add(getAWithGroupList(a, groupA));
}
if(!groupB.isEmpty()){
    finalList.add(getAWithGroupList(a, groupB));
}
if(!groupC.isEmpty()){
    finalList.add(getAWithGroupList(a, groupC));
}
if(!groupD.isEmpty()){
    finalList.add(getAWithGroupList(a, groupD));
}

进入这个for-each循环:

for (List<B> group : new List<B>[]{groupA, groupB, groupC, groupD}) // Packs the lists in an array and iterates over the array
    if(!group.isEmpty())
        finalList.add(getAWithGroupList(a, group));

答案 1 :(得分:1)

最大的障碍是你的标准背后的基本原理是未知的。因此,当我们无法简化它时,我们必须明确声明这些组:

Integer[][] groups={ { 5700, 5750 }, {5800, 5810}, {5802, 5812}, {5803, 5813} };

Map<Integer, Integer[]> type2group = Arrays.stream(groups)
    .collect(HashMap::new, (m,g) -> Arrays.stream(g).forEach(i->m.put(i, g)), Map::putAll);

ArrayList<A> finalList = aList.stream()
    .map(a -> a.getMyList().stream().collect(Collectors.collectingAndThen(
        Collectors.groupingBy(b -> type2group.get(b.getType())),
        group2b -> Arrays.stream(groups)
            .map(g -> group2b.getOrDefault(g, Collections.emptyList()))
            .map(listB -> getAWithGroupList(a, listB))
            .collect(Collectors.toList()))))
    .collect(ArrayList::new, List::addAll, List::addAll);

二维数组是指定这些组的最容易维护的方法。为了在之后有效地处理它们,第一步将它们转换为从类型(B.getType的结果)到所需组的标识符的映射,这只是我们的完整group说明符的子数组(实际的)组标识符的类型是无关紧要的,因为我们将在以后遇到相同的对象,因此数组没有equals方法的事实在这里并不重要。)

第二步为每个B执行A个实例的分组,并组装finalList

请注意,如果没有组,上述解决方案将为它们创建空列表。如果您不想拥有它们,可以将解决方案的最后一步更改为

ArrayList<A> finalList = aList.stream()
    .map(a -> a.getMyList().stream().collect(Collectors.collectingAndThen(
        Collectors.groupingBy(b -> type2group.get(b.getType())),
        group2b -> Arrays.stream(groups)
            .map(g -> group2b.get(g)).filter(Objects::nonNull)
            .map(listB -> getAWithGroupList(a, listB))
            .collect(Collectors.toList()))))
    .collect(ArrayList::new, List::addAll, List::addAll);

或者,以下代码更紧凑,但效率更低,因为它将多次处理数据(遍历每个组的所有B并在组内执行线性搜索):

Integer[][] groups={ { 5700, 5750 }, {5800, 5810}, {5802, 5812}, {5803, 5813} };

List<A> finalList = aList.stream().flatMap(a -> Arrays.stream(groups)
        .map(g -> getAWithGroupList(a, a.getMyList().stream()
            .filter(b -> Arrays.asList(g).contains(b.getType()))
            .collect(Collectors.toList()))))
    .collect(Collectors.toList());

如果可能缺少群组并且您不想为它们设置空列表,则可以将其更改为

List<A> finalList = aList.stream().flatMap(a -> Arrays.stream(groups)
        .map(g -> a.getMyList().stream()
            .filter(b -> Arrays.asList(g).contains(b.getType()))
            .collect(Collectors.toList()))
        .filter(l -> !l.isEmpty())
        .map(l -> getAWithGroupList(a, l)))
    .collect(Collectors.toList());