如何降低流进Java8另一个流?(How to reduce a stream into anoth

2019-10-23 07:41发布

举个例子,我想创建几十像这样的群体的无限流:

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流的群体,而不必收集和再流? (如果可能的话甚至不必使用拳)

Answer 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);


Answer 2:

我怀疑有一种方法,因为你不能从地图顺序在Java 8地图不收取你也不能GROUPBY而不收集。 你可以创建自己的数据流,但我怀疑你真的想要走这条路。

所以,虽然这不是一个答案,我会像这样的东西去,如果你想节省一些时钟周期:

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


Answer 3:

好像如果流是基于另一个流,比它总是有确切的相同数量的条目。

但是我发现了一个patially解决我的问题:我裹消费者变成了“GroupingConsumer”。 这将终止初始流,但仍然能够被infinitly执行。

将得到的代码剪断:

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


Answer 4:

你可以把一个数组与原始的一键式的Map int ,唯一的区别是,而不是仰视通过值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));


文章来源: How to reduce a stream into another stream in Java8?