sortingrandomrandom-access

Exhaust list of elements randomly without sorting them randomly first


If I have a list of 10K elements, and I want to randomly iterate through all of them, is there an algorithm that lets me access each element randomly, without just sorting them randomly first?

In other words, this would not be ideal:

const sorted = list
              .map(v => [math.random(), v])
              .sort((a,b) => a[0]- b[0]);

It would be nice to avoid the sort call and the mapping call. My only idea would be to store everything in a hashmap and access the hash keys randomly somehow? Although that's just coming back to the same problem, afaict.


Solution

  • Fisher-Yates should do the trick as good as any, this article is really good: https://medium.com/@oldwestaction/randomness-is-hard-e085decbcbb2

    the relevant JS code is very short and sweet:

    const fisherYatesShuffle = (deck) => {
      for (let i = deck.length - 1; i >= 0; i--) {
        const swapIndex = Math.floor(Math.random() * (i + 1));
        [deck[i], deck[swapIndex]] = [deck[swapIndex], deck[i]];
      }
      return deck
    }
    

    to yield results as you go, so you don't have to iterate through the list twice, use generator function like so:

    const fisherYatesShuffle = function* (deck) {
        for (let i = deck.length - 1; i >= 0; i--) {
            const swapIndex = Math.floor(Math.random() * (i + 1)); // * use ;
            [deck[i], deck[swapIndex]] = [deck[swapIndex], deck[i]];
            yield deck[i];
        }
    };
    

    (note don't forget some of those semi-colons, when the next line is bracket notation).