Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How get random item from es6 Map or Set

I have a project that uses arrays of objects that I'm thinking of moving to es6 Sets or Maps.

I need to quickly get a random item from them (obviously trivial for my current arrays). How would I do this?

like image 519
backspaces Avatar asked Mar 11 '17 18:03

backspaces


People also ask

How do you pick a random item from an array?

Use Math. random() function to get the random number between(0-1, 1 exclusive). Multiply it by the array length to get the numbers between(0-arrayLength).

How do I randomly select an element from an array in Python?

random. choice() function is used to get random elements from a NumPy array. It is a built-in function in the NumPy package of python.

How do I use the Map function in ES6?

ES6 - Array Method map()map() method creates a new array with the results of calling a provided function on every element in this array.

Are ES6 maps ordered?

Maps are inherently not ordered (except the are iterated insertion order, which requires sorting and then [re-]adding).


2 Answers

Maps and Sets are not well suited for random access. They are ordered and their length is known, but they are not indexed for access by an order index. As such, to get the Nth item in a Map or Set, you have to iterate through it to find that item.

The simple way to get a random item from a Set or Map would be to get the entire list of keys/items and then select a random one.

// get random item from a Set
function getRandomItem(set) {
    let items = Array.from(set);
    return items[Math.floor(Math.random() * items.length)];
}

You could make a version that would work with both a Set and a Map like this:

// returns random key from Set or Map
function getRandomKey(collection) {
    let keys = Array.from(collection.keys());
    return keys[Math.floor(Math.random() * keys.length)];
}

This is obviously not something that would perform well with a large Set or Map since it has to iterate all the keys and build a temporary array in order to select a random one.


Since both a Map and a Set have a known size, you could also select the random index based purely on the .size property and then you could iterate through the Map or Set until you got to the desired Nth item. For large collections, that might be a bit faster and would avoid creating the temporary array of keys at the expense of a little more code, though on average it would still be proportional to the size/2 of the collection.

// returns random key from Set or Map
function getRandomKey(collection) {
    let index = Math.floor(Math.random() * collection.size);
    let cntr = 0;
    for (let key of collection.keys()) {
        if (cntr++ === index) {
            return key;
        }
    }
}
like image 70
jfriend00 Avatar answered Sep 28 '22 03:09

jfriend00


There's a short neat ES6+ version of the answer above:

const getRandomItem = iterable => iterable.get([...iterable.keys()][Math.floor(Math.random() * iterable.size)])

Works for Maps as well as for Sets (where keys() is an alias for value() method)

like image 44
allx Avatar answered Sep 28 '22 03:09

allx