2014-08-29 46 views
4

我很努力地找到一種方法,以根據謂詞在流的開始處跳過某些​​元素。Scala的等效下降時間

事情是這樣的:

dropWhile(n -> n < 3, Stream.of(0, 1, 2, 3, 0, 1, 2, 3, 4)) 
.forEach(System.out::println); 
3 
0 
1 
2 
3 
4 

也就是說斯卡拉dropWhile的等價物。

+0

相關:限制由一個謂語流(http://stackoverflow.com/q/ 20746429) – charlie 2016-06-28 12:31:06

回答

9

這種操作不是Stream的預期用例,因爲它包含元素之間的依賴關係。

class MutableBoolean { boolean b; } 
MutableBoolean inTail = new MutableBoolean(); 

IntStream.of(0, 1, 2, 3, 0, 1, 2, 3, 4) 
     .filter(i -> inTail.b || i >= 3 && (inTail.b = true)) 
     .forEach(System.out::println); 

注意,病情比你的例子被逆轉:所以你就來介紹你的謂詞全狀態變量的解決方案可能不會顯得高貴典雅。

當然,你可以隱藏在方法的骯髒細節:

public static void main(String... arg) { 
    dropWhile(n -> n < 3, Stream.of(0, 1, 2, 3, 0, 1, 2, 3, 4)) 
     .forEach(System.out::println); 
} 
static <T> Stream<T> dropWhile(Predicate<T> p, Stream<T> s) { 
    class MutableBoolean { boolean b; } 
    MutableBoolean inTail = new MutableBoolean(); 
    return s.filter(i -> inTail.b || !p.test(i) && (inTail.b = true)); 
} 

更復雜,但更清潔,可能更有效的辦法是深入到金屬,即Spliterator接口:

static <T> Stream<T> dropWhile(Predicate<T> p, Stream<T> s) { 
    Spliterator<T> sp = s.spliterator(); 
    return StreamSupport.stream(new Spliterators.AbstractSpliterator<T>(
      sp.estimateSize(), sp.characteristics() & ~Spliterator.SIZED) { 
     boolean dropped; 
     public boolean tryAdvance(Consumer<? super T> action) { 
      if(dropped) return sp.tryAdvance(action); 
      do {} while(!dropped && sp.tryAdvance(t -> { 
       if(!p.test(t)) { 
        dropped=true; 
        action.accept(t); 
       } 
      })); 
      return dropped; 
     } 
     public void forEachRemaining(Consumer<? super T> action) { 
      while(!dropped) if(!tryAdvance(action)) return; 
      sp.forEachRemaining(action); 
     } 
    }, s.isParallel()); 
} 

這種方法可以使用方式與第dropWhile方法相同,但它的工作即使並行流,因爲你米,雖然效率不高願望。

+0

有點晚了,但你有沒有考慮使用'AtomicBoolean'而不是'MutableBoolean'類? – Henrik 2017-02-17 12:59:05

+1

@Henrik:由於謂詞評估的順序是未定義的,因此'AtomicBoolean'會假裝不存在此操作的線程安全性。此外,您可能會潛在地浪費性能,使用線程安全構造執行無法並行工作的操作。另一方面,本地使用的'MutableBoolean'則清楚地顯示了您所期望的。 – Holger 2017-02-17 13:12:31

+0

很好的解釋!謝謝。 – Henrik 2017-02-17 13:13:11

6

不幸的是,使用Java 8的唯一方法是使用由Holger提供的解決方案。

但是,操作dropWhile(predicate)一直added to Java 9所以從JDK 9日起,你可以簡單地有:

Stream.of(0, 1, 2, 3, 0, 1, 2, 3, 4).dropWhile(n -> n < 3).forEach(System.out::println);