IntStream的随机排列

时间:2019-02-19 16:51:37

标签: java java-stream

我时不时地发现自己处于索引循环中,为此,我想将其顺序排列为一些随机顺序。 我通常会从类似

的地方过渡
for (int i = 0; i < max; i++) {
    // do stuff with i
}

List<Integer> indices = IntStream.range(0, max)
    .boxed()
    toCollection(() -> new ArrayList(max)));
Collections.shuffle(indices);
for (int i = 0; i < max; i++) {
    int index = indices.get(i);
    // do stuff with index
}

这既不高效也不优雅。是否可以在一定范围内创建Stream(理想情况下为IntStream),但是否让其元素改组?我在想一些类似的事情:

IntStream.range(0, max)
        .shuffled() // this method doesn't exist
        .forEach(IntConsumer::accept);

生成的IntStream仍应一次准确地包含[0, max)范围内的所有元素。


这不是this question的副本,因为我不想创建List并对其进行洗牌。由于该解决方案可与Integer一起使用,因此会产生大量开销,同时还会冗余地创建和改组List。我已经在自己的示例中提供了该解决方案,因此我完全了解该方法。

2 个答案:

答案 0 :(得分:5)

这个怎么样?您几乎拥有了同样的东西,除了它封装了所有的坚韧不拔的东西,只为您提供了一个纯IntStream。另外,它也不必进行太多装箱和拆箱操作。

public class ShuffledIntStream {

    public static IntStream to(int max) {
        Random r = new Random();
        int[] values = new int[max];
        for (int i = 0; i < max; i++) {
            values[i] = i;
        }
        for (int i = max; i > 1; i--) {
            swap(values, i - 1, r.nextInt(max));
        }
        return IntStream.of(values);
    }

    private static void swap(int[] values, int i, int j) {
        int temp = values[i];
        values[i] = values[j];
        values[j] = temp;
    }
}

答案 1 :(得分:1)

您可以使用Random.ints

new Random().ints(0, max)
    .distinct()
    .limit(max)
    .forEach(IntConsumer::accept);

ints会在0max之间产生一个整数流,distinct确保没有重复项,而limit则会得到精确的很多你想要的。