如何使用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]]]
下面呢?
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”。
希望这有帮助。
你为什么不干脆写这个?
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();
}
流相当于
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),等等,你能解释一下我在哪里犯了错误吗?