Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Random permutation of IntStream

Every now and then I find myself with indexed loops, for which I want to permutate the order to some random order. I usually transition from something like

for (int i = 0; i < max; i++) {
    // do stuff with i
}

to

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
}

This is neither efficient nor elegant. Is it possible to create a Stream (ideally an IntStream) in a certain range, but have it return its elements shuffled? I am thinking of something along the lines of:

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

The resulting IntStream should still include all elements in the range [0, max) exactly once.


This is not a duplicate of this question, because I don't want to create a List and shuffle it. This solution has a massive overhead since it is working with Integers, while also redundantly creating and shuffling a List. I have provided that solution in my own example, so I am fully aware of that approach.

like image 679
Neuron Avatar asked Feb 19 '19 16:02

Neuron


1 Answers

How about this? It's pretty much the same thing you have, except it encapsulates all the nitty gritty and just gives you a pure IntStream. Also it doesn't have to do so much boxing and unboxing.

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;
    }
}
like image 153
Willis Blackburn Avatar answered Sep 24 '22 19:09

Willis Blackburn