2014-09-02 32 views
7

Bir akıştaki öğeleri aynı türden bir ayırıcıyla birleştirmek için Java akışlarını kullanmanın güzel bir yolu var mı?Ayırıcı içeren bir akıştaki ara elemanlar

// Expected result in is list: [1, 0, 2, 0, 3] 
List<Integer> is = Stream.of(1, 2, 3).intersperse(0).collect(toList()); 

Bu Haskell ve diğer fonksiyonel dillerde intersperse işlevine benzer.

Dizeleri benzer şekilde birleştirmenin birçok örneğini gördüm ancak genel listeler için herhangi bir çözüm bulamadılar.

cevap

8

Sen flatMap ile yapabilirsiniz, ancak son öğe sonra ek ayırıcı alırsınız: Burada

List<Integer> is = IntStream.of(1, 2, 3) 
          .flatMap(i -> IntStream.of(i, 0)) 
          .collect(toList()); 

sondaki ayırıcı olmadan, başka bir yol:

List<Integer> is = IntStream.of(1, 2, 3) 
          .flatMap(i -> IntStream.of(0, i)) 
          .skip(1) 
          .collect(toList()); 

Bu sefer Her orijinal elemandan önce ayırıcıyı ekleyin ve önde gelen ayırıcıdan kurtulun.

static <T> Collector<T,List<T>,List<T>> intersperse(T delim) { 
    return Collector.of(ArrayList::new, (l,e)-> { 
     if(!l.isEmpty()) l.add(delim); 
     l.add(e); 
    }, (l,l2)-> { 
     if(!l.isEmpty()) l.add(delim); 
     l.addAll(l2); 
     return l; 
    }); 

o zaman benzer Collectors.joining(delimiter) için kullanabilirsiniz::

+0

+1 boyutunu biliyorsanız 'n' Orijinal listeden '.limit (2 * n-1)' kullanabilirsiniz. –

+0

@tobias_k Bu doğru – Eran

+0

Teşekkür ederiz. Ancak takip eden bir ayırıcı almamak, bir nokta. Ve burada 'limit' kullanmak biraz fazla sakar. Ama aynı zamanda bir ayrılıkçı istediğiniz zaman için bir çözüm olması iyi! – Lii

6

Sen Collectors.joining bir küçük yardımcı yöntemiyle String s yapar benzer bir şey yapabilir

List<Integer> l=Stream.of(1, 2, 3).collect(intersperse(0)); 

üretir

[1, 0, 2, 0, 3]

Bu işlemin, collect korumaları nedeniyle bu iş parçacığı için güvenli olduğunu unutmayın.


Eğer bir liste halinde toplamak ama bu şekilde yapabiliriz bir ara akım operasyonu olarak sınırlayıcılar eklemek istemiyorsanız:

Integer delimiter=0; 
Stream.of(1, 2, 3)/** or any other stream source */ 
     .map(Stream::of) 
     .reduce((x,y)->Stream.concat(x, Stream.concat(Stream.of(delimiter), y))) 
     .orElse(Stream.empty()) 
     /* arbitrary stream operations may follow */ 
+0

İlginç çözümler! – Lii

+0

Ben .map (Stream :: of) hile seviyorum. 'UnflatMap' gibi bir sıralama. – Lii