是否可以使用Streams.intRange函数?

时间:2015-09-15 12:51:20

标签: java java-8 java-stream

我想使用Streams.intRange(int start,int end,int step)来实现反向排序流。但是,似乎java.util.Streams类不再可用(但它仍然在标准库中的rt.jar中)。这个方法是在其他类中还是用其他类替换了?

3 个答案:

答案 0 :(得分:4)

到目前为止提出的两种解决方案都不尊重并行化。 @fge提出的分裂器根本不是并行化的。 @RealSkeptic提出的基于迭代的流将使用缓冲并行化(一些数字将加载到中间数组并移交给另一个线程),这并不总是有效。

提供正常并行化的非常简单的替代解决方案(此处end是独占的):

public static IntStream intRange(int start, int end, int step ) {
    int limit = (end-start+step-(step>>31|1))/step;
    return IntStream.range(0, limit).map(x -> x * step + start);
}

或者,如果你想考虑像intRange(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE)这样奇怪的输入:

public static IntStream intRange(int startInclusive, int endExclusive, int step) {
    if(step == 0)
        throw new IllegalArgumentException("step = 0");
    if(step == 1)
        return IntStream.range(startInclusive, endExclusive);
    if(step == -1) {
        // Handled specially as number of elements can exceed Integer.MAX_VALUE
        int sum = endExclusive+startInclusive;
        return IntStream.range(endExclusive, startInclusive).map(x -> sum - x);
    }
    if((endExclusive > startInclusive ^ step > 0) || endExclusive == startInclusive)
        return IntStream.empty();
    int limit = (endExclusive-startInclusive)*Integer.signum(step)-1;
    limit = Integer.divideUnsigned(limit, Math.abs(step));
    return IntStream.rangeClosed(0, limit).map(x -> x * step + startInclusive);
}

答案 1 :(得分:1)

JDK中确实没有这样的方法;你可以获得的下一个最接近的是IntStream.range(),但这只会一步一步。

这里的一个解决方案是实现自己的Spliterator.OfInt;比如像这样的东西(非常粗糙;可以改进!):

public final class StepRange
    implements Spliterator.OfInt
{
    private final int start;
    private final int end;
    private final int step;

    private int currentValue;

    public StepRange(final int start, final int end, final int step)
    {
        this.start = start;
        this.end = end;
        this.step = step;
        currentValue = start;
    }

    @Override
    public OfInt trySplit()
    {
        return null;
    }

    @Override
    public long estimateSize()
    {
        return Long.MAX_VALUE;
    }

    @Override
    public int characteristics()
    {
        return Spliterator.IMMUTABLE | Spliterator.DISTINCT;
    }

    @Override
    public boolean tryAdvance(final IntConsumer action)
    {
        final int nextValue = currentValue + step;
        if (nextValue > end)
            return false;
        action.accept(currentValue);
        currentValue = nextValue;
        return true;
    }
}

然后,您将使用StreamSupport.intStream()从上面的类的实例生成您的流。

答案 2 :(得分:0)

您可以根据无限流创建它:

public static IntStream intRange(int start, int end, int step ) {
    if ( step == 0 ) {
        throw new IllegalArgumentException("Cannot iterate with a step of zero");
    }
    final int limit = (end - start + step) / step;
    if ( limit < 0 ) {
        return IntStream.empty();
    }
    return IntStream.iterate(start, x -> x + step )
                    .limit( limit );
}

如果范围没有意义(例如,以1为单位从7到2的范围),则会得到一个空的流。

限制包含在内。也就是说,2到2的范围从2到8将给你2,4,6,8。如果您希望它是独占的(没有8),请将限制更改为:

final int limit = (end - start) / step;

可能的用法:

intRange(8 ,2, -2).forEach(System.out::println);

输出:

8
6
4
2