我有一个使用对象数组的项目,我正在考虑转移到es6集或地图。
我需要快速从它们中获取一个随机项(对于我当前的数组来说显然是微不足道的)。我该怎么做?
答案 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()方法的别名)