2016-05-30 45 views
13

Bir rasgele sınıfa ait Collection öğem var. Koleksiyonda yineleme yapmak ve elementi ve koleksiyonun her bir elemanını tek tek kullanarak (elemanın kendisi hariç) bir miktar işlem yapmak istiyorum. o basitlik için List<Integer> olalım: for ileJava 8 akışları: listeden olası her eleman çifti

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); 

öyle olacak döngülerin:

for (Integer i : list) { 
    for (Integer j : list) { 
     if (!i.equals(j)) System.out.println(i * 2 + j); //just for example 
    } 
} 

soru nasıl Stream API ile yapmak nedir?

list.stream().forEach(i -> 
    list.stream().forEach(j -> { 
     if (!i.equals(j)) System.out.println(i * 2 + j); 
    }) 
); 

olsa iç içe döngü daha iyi görünmüyor: Ben geldim ne

. Daha zarif bir yolu var mı?

cevap

13

Sen flatMap işlemi kullanarak bunu yapabilirsiniz: Bu kod giriş listesinin bir Akışı yaratıyor

list.stream() 
    .flatMap(i -> list.stream().filter(j -> !i.equals(j)).map(j -> i * 2 + j)) 
    .forEach(System.out::println); 

. Listenin her bir öğesi, aynı öğenin oluşturduğu bir akışla, geçerli öğenin filtrelenmiş olduğu ve bu yeni listenin her öğesinin i * 2 + j işleminin sonucu olduğunu gösteren düz eşlemelere eşler.

Tüm elemanlar daha sonra konsola yazdırılır.

6

Önceden, örneğin, int değerlerini eşleyerek nesne karşılaştırmalarını önleyebilirsiniz.

list.stream().mapToInt(Integer::intValue) 
    .flatMap(i -> list.stream().filter(j -> j!=i).mapToInt(j -> i*2 + j)) 
    .forEach(System.out::println); 

Aslında, aslında, değişmez bir şey için koşullu işlemler ve eşitlik denetimleri gerçekleştiriyorsunuz. Tüm operasyon arasına-içeriğini değiştirerek kaynak listede dayandığı için, sadece ilk etapta eşleştirme listesi indeksleri oluşturabilir:

durumda
final int end=list.size(); 
IntStream.range(0, end).flatMap(i -> 
    IntStream.concat(IntStream.range(0, i), IntStream.range(i+1, end)) 
     .map(j -> list.get(i) * 2 + list.get(j))) 
    .forEach(System.out::println); 

sayısal bir değeri hesaplamak istemiyoruz ama çiftler için bir nesne oluşturmak, IntStream'un flatMapToObj işlemine sahip olmamasından dolayı biraz daha karmaşıklaşır, bu nedenle mapToObj ve flatMap (kullanmıyorsak) (boxed kullanmıyorsak). Bir List ile uğraşmadan, [ 1, 2, 3, 4, 5 ] kadar basit bir liste, sadece ilk etapta IntStream.rangeClosed(1, 5) kullanabileceğinden, Tabii

IntStream.range(0, end).mapToObj(i -> 
    IntStream.concat(IntStream.range(0, i), IntStream.range(i+1, end)) 
     .mapToObj(j -> new int[]{ list.get(i), list.get(j)})) 
     .flatMap(Function.identity()) 
    .forEach(a -> System.out.println(a[0]*2+a[1])); 

: Yani iki uzunluk dizisi ve örnek teşkil inşa benziyor

IntStream.rangeClosed(1, 5).flatMap(i -> 
     IntStream.concat(IntStream.range(1, i), IntStream.rangeClosed(i+1, 5)) 
     .map(j -> i*2 + j)) 
    .forEach(System.out::println);