2015-06-06 59 views
1

舉個例子,我想這樣創建的組數無限流:如何在Java8中將流簡化爲另一個流?

0=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
1=[10, 11, 12, 13, 14, 15, 16, 17, 18, 19] 
2=[20, 21, 22, 23, 24, 25, 26, 27, 28, 29] 
... 

我想使用的int inifinte流作爲輸入,然後進行分組。如果第一個流迭代10次,則結果流只應迭代一次。

我的工作,但不是很優雅的代碼看起來是這樣的:

// create a stream from 0 (inclusive) to 100 (exclusive) 
IntStream.iterate(0, i -> i+1).boxed().limit(100) 

// slow down 
.peek((i) -> {try {Thread.sleep(50);} catch (InterruptedException e) {}}) 

// group by tens 
/* ugly: */.collect(Collectors.groupingBy(i -> i/10)).entrySet() 
/* not working: */ //.makeSequentialGroups(i -> i/10) 

// print to console 
.forEach(System.out::println); 

如何使一個int流的羣體,而不必收集和再流? (如果可能的話,即使不必使用拳擊)

+0

您不必創建另一個流,可以在'Set'中使用'forEach'方法。 – Bubletan

+0

@Bubletan感謝您的提示,我更新了我的問題,不再包含過時的'forEach' – slartidan

回答

1

這樣的功能在我的StreamEx庫可用,並呼籲groupRuns:您可以收集相鄰元素融入基於中間名單提供的謂詞。例如:

IntStreamEx.iterate(0, i -> i+1).boxed().limit(100) 
    .peek((i) -> {try {Thread.sleep(50);} catch (InterruptedException e) {}}) 
    .groupRuns((a, b) -> a/10 == b/10) 
    .forEach(System.out::println); 
+0

感謝您的回答。你的圖書館看起來很有用! – slartidan

2

我懷疑有沒有辦法,因爲你不能從sequence to a Map in java 8沒有收集地圖,也不可以groupBy沒有收集。你可以創建自己的流,但我懷疑你真的想走那條路。

所以,雖然這不是一個答案,我會像這樣的東西去,如果你想節省一些時鐘週期:

IntStream.range(0, 10) 
      .boxed() 
      .collect(Collectors.toMap(
       Function.identity(), 
       (x) -> IntStream.range(x * 10, x * 10 + 10) 
     )) 
1

好像如果流是基於另一個流,比它總是必須具有完全相同的條目數量。

但是,我發現了一個問題的解決方案:我將消費者包裝到「GroupingConsumer」中。這將終止初始流,但仍然能夠無限地執行。

剪斷生成的代碼:

// create a stream from 0 (inclusive) to infinity! 
IntStream.iterate(0, i -> i+1).boxed() 

// slow down 
.peek((i) -> {try {Thread.sleep(50);} catch (InterruptedException e) {}}) 

// terminate the stream of single items (ungrouped) 
.forEach(

    // create a wrap-around 
    GroupingConsumer.create(

     // define the grouping rule 
     i -> i/10, 

     // the wrapped consumer 
     System.out::println 
)); 

GroupingConsumer類:

import java.util.AbstractMap.SimpleEntry; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Map.Entry; 
import java.util.function.Consumer; 
import java.util.function.Function; 

/** 
* Forwards a group of items, whenever the grouping-key changes 
* 
* @param <K> the type of the grouping key 
* @param <T> the type of the single entries 
*/ 
class GroupingConsumer<K, T> implements Consumer<K> { 

    private Function<K, T> keyCalculator; 
    private Consumer<Entry<T, List<K>>> consumer; 

    Entry<T, List<K>> currentGroup; 

    /** 
    * Wraps your consumer, so that it will get groups of items instead of single items. 
    * 
    * @param keyCalculator the "grouping by" 
    * @param consumer your consumer, that will be called less frequently 
    * @return the wrapped consumer 
    */ 
    public static <K, T> GroupingConsumer<K,T> create(Function<K, T> keyCalculator, Consumer<Entry<T, List<K>>> consumer) { 
     GroupingConsumer<K, T> groupingConsumer = new GroupingConsumer<K, T>(); 
     groupingConsumer.consumer = consumer; 
     groupingConsumer.keyCalculator = keyCalculator; 
     return groupingConsumer; 
    } 

    @Override 
    public void accept(K nextValue) { 
     T key = keyCalculator.apply(nextValue); 

     boolean newGroupRequired = false; 

     if (currentGroup == null) 
      newGroupRequired = true; 
     else if (!currentGroup.getKey().equals(key)) { 
      newGroupRequired = true; 
      consumer.accept(currentGroup); 
     } 

     if (newGroupRequired) 
      currentGroup = new SimpleEntry<T, List<K>>(key, new ArrayList<K>()); 
     currentGroup.getValue().add(nextValue); 
    } 
} 
0

你可以把一個數組與原始int一鍵式Map的,唯一的區別是,而不是通過map.get(i)尋找一個值,你通過myArray[i]查找一個值。按照您的要求,使用數組對數組進行分組也可以避免使用拳擊。這是一個解決方案,可以在沒有裝箱的情況下產生類似的結果

int[][] results = IntStream.iterate(0, i -> i + 10) 
      .limit(10) 
      .mapToObj(i -> (int[]) IntStream.range(i, i + 10).toArray()) 
      .toArray(int[][]::new); 

    System.out.println(Arrays.deepToString(results)); 
相關問題