2016-06-27 45 views
0

如何過濾使用java8流和過濾器的嵌套循環?如何使用Java 8流和過濾器過濾嵌套循環?

假設我有一個汽車列表(List<Car>),每輛汽車都有一個引擎列表(List<Engine>),每個引擎有一個List<Parts>

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()); 
}}); 

如果我想篩選出的List<Engine>空,然後我會做

在常規的Java作爲這種結構可以描述
cars.stream().filter(p -> p.getEngines() != null).forEach(System.out::println); 

如果我想過濾列表的空列表,那麼我會做

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

但是,如何刪除第3輛汽車中的空Engine,而是將其他兩個引擎連接到原始列表結構?換句話說,我們可以使用Java 8過濾器進入第2層,第3層還是第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 

問題:我們如何使用Java 8 .filter,這樣,當過濾後,我得到如下結果:

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 

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

又如

傢伙,我希望這個例子,我只是做了更清晰:..本質上,它是與上面相同,只是它更詳細而不是c我們可以想到銀行最大限度地減少抽象。爲了簡明起見,我公開了所有的字段,我希望你不介意。這裏
我身體行:

假設我有4家銀行下屬在我的銀行錢包'
銀行#1。我不得不擁有3個賬戶,但只有2個有一些現金和第三個尚未開立(即空)
銀行2:
我打算在這裏銀行。創建帳戶支持結構(空ArrayList),但不添加帳戶
銀行#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]]] 

問: 什麼其他的過濾器,我需要做添加到代碼,以獲得上述結果不會顯示在賬戶空,但仍保留了整體結構(銀行 - >帳戶 - > etc->等)

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

在外部列表中的每個條目上運行映射。 map函數應該過濾出你不想要的東西。 –

+2

你能更具體地說明你想用你的循環實現什麼嗎?我認爲安德烈亞斯提出了一個很好的觀點,告訴我我對你正在尋找的東西做了太多的假設,因爲你的問題不夠具體。只需給我們一個樣本輸入以及所需的輸出 – Dici

+0

因此,您想打印整輛車,不包括任何空/空組件? – shmosel

回答

2

你爲什麼不簡單地寫這個?

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(); 
} 
+3

'getEngines()'返回'列表'(或類似的),它沒有'getParts'。 – Andreas

+1

@Andreas固定,歡呼 – Dici

+1

的'的System.out :: println'將每進行一次'Car',這是*非常*不同的結果比'for'循環代碼,將執行'叫...'爲每個「部分」。 – Andreas

3

流等效的

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 -> { /* ... */ }); 

...代碼將然而不必carengine訪問。

要檢查空,你可以在兩個地方檢查:

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 -> { /* ... */ }); 
+1

他想顯示汽車,而不是零件(從我的理解)。這就是爲什麼'flatMap'不能在這裏使用,或者不這樣。我們不想失去對汽車的參考。此外,所有的片段都可以拋出'NullPointerException' – Dici

+0

這是非常好的,但作爲@Dici指出的那樣,我要顯示的汽車沒有部件本身。 – JavaFan

+1

@JavaFan如何文本*「但我怎麼刪除空引擎在第三汽車,但保持其他兩個引擎安裝到原來的目錄結構?」 *搖擺只想要的車?如果你只想開車,過濾引擎列表的整個過程是什麼?那麼與零件清單有什麼關係?當然,擁有多臺發動機的汽車的概念並不常見。 – Andreas

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部分DefaultPart引擎C2E2部分DefaultPart

有重寫 「的toString」 對於汽車/發動機/部分類。

希望這會有所幫助。