当前位置: 首页 > 知识库问答 >
问题:

如何使用Java8流和过滤器过滤嵌套循环?

邢和光
2023-03-14

如何使用java8流和过滤器过滤嵌套循环?

假设我有一个汽车列表(list

for(Car car : cars) {
    for (Engine engine : car.getEngines()) {
        for (Part part : engine.getParts()) {
            // ...
        }
    }
}

假设我将汽车列表初始化为:

List<Car> cars =  new ArrayList<Car>(Arrays.asList(new Car(), new Car(), new Car()));
cars.get(0).setEngines(null);
cars.get(1).setEngines(new ArrayList<Engine>());
cars.get(2).setEngines(new ArrayList<Engine>() {{
    add(new Engine());
    add(null);
    add(new Engine());  
}});

如果我想过滤掉列表中的空值

cars.stream().filter(p -> p.getEngines() != null).forEach(System.out::println);

如果我想过滤掉列表中的空ArrayList,那么我会这样做

cars.stream().filter(p -> !p.getEngines().isEmpty()).forEach(System.out::println);

但是如何在第三辆车中删除空的引擎,同时将另外两个引擎连接到原始列表结构?换句话说,我们可以使用Java8过滤器进入层次结构的第二、第三、第n层,还是过滤器只在最顶层工作?我还尝试使用。anyMatch(),运气不好。

为了进一步澄清,考虑下面的例子:我的车库里有3辆车。每辆车有3个发动机占位符。每个引擎有3个占位符,用于组成引擎的部件:

Car #1: 
 Engine#1: part1, part2, part3
 Engine#2: null, part2, empty
 Engine#3: part1, null, part3
Car #2: 
 Engine#1: part1, part2, part3
 empty:    null, null, null
 null:     null, null, null
Car #3: 
 Engine#1: null, empty, part3
 Engine#2: null, part2, empty
 Engine#3: part1, null, part3

问题:我们如何使用Java8。过滤,这样在过滤后我会得到以下信息:

Car #1: 
 Engine#1: part1, part2, part3
 Engine#2: part2, 
 Engine#3: part1, part3
Car #2: 
 Engine#1: part1, part2, part3
Car #1: 
 Engine#1: part3
 Engine#2: part2,
 Engine#3: part1,part3

=======================

伙计们,我希望我刚刚编的这个例子更清楚:...本质上,它和上面的一样,只是更冗长,我们可以想到银行来减少抽象。为了简洁起见,我公开了所有领域,希望你不要介意。

假设我在我的银行钱包里有4家银行
银行#1:
我实际上在这里银行。我被迫有3个账户,但只有2个装满了一些现金,第三个尚未打开(即空)
银行#2:
我计划在这里银行。帐户支持结构被创建(空ArrayList),但是没有添加帐户
Bank#3:
我填写了一些营销表单。他们的客户关系管理中有我,但是没有账户会被打开
银行#4:
这家银行被烧毁了,钱包里有一个神器占位符,它是空的。

以下代码对此进行了描述:

public class Bank_Wallet {

    public static void main(String[] args) {
        List<Bank> banks = new ArrayList<Bank>(Arrays.asList(new Bank(), new Bank(), new Bank(), null));
        // 1st bank with physical accounts, but one of them is null
        banks.get(0).accounts = Arrays.asList(new Account(), null, new Account());
        // 2nd bank with empty accounts  
        banks.get(1).accounts = new ArrayList<Account>();

        System.out.println("RAW original");
        banks.stream().forEach(System.out::println);

        System.out.println("\nFiltered result...   ");
        banks.stream()// get stream
                .filter(p -> p != null) // get rid of null banks
                .filter(p -> p.accounts != null) // get rid of null accounts
                .filter(p -> !p.accounts.isEmpty()) // get rid of empty accounts
                // .filter(p->p.accounts. ?????? ??) ?? how do I remove null account from the remaining bank entry?
                .forEach(System.out::println);

    }// main
}


支持类在这里:

public class Bank {
    public String name;
    public static int counter = 0;
    public List<Account> accounts;

    public Bank() {
        this.name = "Bank: #" + Bank.counter++;
    }

    @Override
    public String toString() {
        return "Bank [name=" + this.name + ", accounts=" + this.accounts + "]";
    }

public class Account {
    public String name;
    public static int counter;

    public Account() {
        this.name = "Account: " + Account.counter++;
    }

    @Override
    public String toString() {
        return "Account [name=" + this.name + "]";
    }

}

当您运行此代码时,您将看到在建议的筛选之后,我剩下的就是

Bank [name=Bank: #0, accounts=[Account [name=Account: 0], null, Account [name=Account: 1]]]

问题:我需要向代码中添加什么其他过滤器,以使上述结果在帐户中不显示空值,同时保留整体结构(银行)-

Bank [name=Bank: #0, accounts=[Account [name=Account: 0], Account [name=Account: 1]]]

共有3个答案

单勇
2023-03-14

下面呢?

    List<Car> cars = new ArrayList<Car>(Arrays.asList(new Car("C0"), new Car("C1"), new Car("C2")));
    cars.get(0).setEngines(new ArrayList<Engine>());
    cars.get(1).setEngines(new ArrayList<Engine>());
    cars.get(2).setEngines(Arrays.asList(new Engine("C2E1"), new Engine("C2E2"), null));

    cars.stream().filter(c -> Objects.nonNull(c.getEngines())).forEach(c -> {
        System.out.printf("Car %s ", c);
        c.getEngines().stream().filter(e -> Objects.nonNull(e) && Objects.nonNull(e.getParts())).forEach(e -> {
            System.out.printf(" Engine %s ", e);
            e.getParts().stream().filter(p -> Objects.nonNull(p))
                    .forEach(p -> System.out.printf("Part %s", p));
        });
        System.out.println();
    });

产生以下结果:

汽车C0

C1车

汽车C2引擎C2E1零件默认零件引擎C2E2零件默认零件

已覆盖汽车/发动机/零件类别的“toString”。

希望这有帮助。

乐健
2023-03-14

你为什么不干脆写这个?

cars.stream()
    .filter(car -> notEmpty(car.getEngines()))
    .filter(car -> car.getEngines().stream().allMatch(engine -> notEmpty(engine.getParts())))
    .forEach(System.out::println);

public static <T> boolean notEmpty(Collection<T> collection) {
   return collection != null && !collection.isEmpty();
}
黄成荫
2023-03-14

流相当于

for(Car car : cars) {
    for (Engine engine : car.getEngines()) {
        for (Part part : engine.getParts()) {
            // ...
        }
    }
}

cars.stream()
    .flatMap(car -> car.getEngines().stream())
    .flatMap(engine -> engine.getParts().stream())
    .forEach(part -> { /* ... */ });

代码将无法访问汽车发动机

要检查null,您可以在两个地方进行检查:

cars.stream()
    .flatMap(car -> car.getEngines().stream())
    .filter(engine -> engine != null)
    .flatMap(engine -> engine.getParts().stream())
    .forEach(part -> { /* ... */ });

cars.stream()
    .flatMap(car -> car.getEngines()
                       .stream()
                       .filter(engine -> engine != null))
    .flatMap(engine -> engine.getParts().stream())
    .forEach(part -> { /* ... */ });

 类似资料:
  • 我有两个简单的POJOs: 然后我生成一些数据,我为父母添加100个孩子: 我的目标是移除所有10岁以下的儿童: 最后,我列出了十岁以上的孩子。但是我不想写一个单独的方法。 如何得到所有的父母与名单上的孩子十岁以上只使用单一流?

  • 我有一个对象的集合,每个对象都有一个元素的集合,例如: 如何使用Java 8函数式编程来过滤和收集类型等于“a”的集合? 我尝试了以下方法: 但我得到以下错误: 变量'filteredChildren'初始值设定项'parents。stream()。forEach(p- 如何按类型筛选嵌套集合并收集它们?

  • 假设我有一张房间清单 每个房间都有一份人员名单。 使用java8 streams,我想迭代房间列表,获取所有人员,在每个节点上执行一些方法(doSomething()),并获取所有过滤对象的列表。 这是使用java 8的最佳实践吗?

  • 我正在用Java8为一个文件编写一个解析器。使用读取该文件,并返回一个顺序的。 每一行都映射到一个数据对象,如下所示: 现在我们可以将流中的每一行映射到相应的结果: 但是,流现在包含要删除的值: 如我在中所知,如果需要结果,我如何组合映射/筛选操作?

  • 有两个具有相同结构的地图,即map1和map2,其结构为

  • 将此流收集到列表中 正如我所看到的,infinity循环有一些问题,所以peek()打印范围内的数字(12,99),这是可以的,但之后它再次打印范围内的数字(11,98),等等,你能解释一下我在哪里犯了错误吗?