如何从es6 Map或Set中获取随机项

时间:2017-03-11 18:54:49

标签: dictionary ecmascript-6 set

我有一个使用对象数组的项目,我正在考虑转移到es6集或地图。

我需要快速从它们中获取一个随机项(对于我当前的数组来说显然是微不足道的)。我该怎么做?

2 个答案:

答案 0 :(得分:8)

地图和集合不适合随机访问。它们是有序的,它们的长度是已知的,但它们没有被索引用于订单索引的访问。因此,要在Map或Set中获取第N个项目,您必须遍历它才能找到该项目。

从Set或Map中获取随机项的简单方法是获取整个键/项列表,然后选择一个随机项。

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

您可以创建一个既适用于Set又适用于Map的版本:

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

这显然不适合使用大型Set或Map,因为它必须迭代所有键并构建一个临时数组才能选择一个随机数组。

由于Map和Set都具有已知大小,您还可以纯粹基于.size属性选择随机索引,然后您可以迭代Map或Set,直到达到所需的第N个项目。对于大型集合,这可能会更快一点,并且会避免以更多代码为代价创建临时密钥数组,尽管平均而言它仍然与集合的大小/ 2成比例。

// 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;
        }
    }
}

答案 1 :(得分:0)

上面的答案有一个简洁的ES6 +版本:

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

适用于地图和集合(其中keys()是value()方法的别名)