繁体   English   中英

从数组中选取 2 个随机元素

[英]Picking 2 random elements from array

从数组中选择 2 个唯一随机元素的最有效方法是什么(即,确保同一元素未被选择两次)。

我到目前为止:

var elem1;
var elem2;

elem1 = elemList[Math.ceil(Math.random() * elemList.length)];
do {
  elem2 = elemList[Math.ceil(Math.random() * elemList.length)];
} while(elem1 == elem2)

但这经常挂起我的页面加载。

有更好的解决方案吗?

额外的问题,我如何将其扩展到n元素

不要使用循环和比较。 反而

  • 打乱数组
  • 取前两个元素

http://underscorejs.org/#sample

_.sample(list, [n])

从列表中生成一个随机样本。 传递一个数字以从列表中返回 n 个随机元素。 否则将返回单个随机项目。

_.sample([1, 2, 3, 4, 5, 6]);
=> 4

_.sample([1, 2, 3, 4, 5, 6], 3);
=> [1, 6, 2]

查看它使用shuffle的来源,就像@thg435 建议的那样。

当列表仅包含一项时,您的代码将挂起。 我建议使用===而不是使用== ,这在这种情况下看起来更合适。

另外,使用Math.floor而不是Math.ceil length属性等于<highest index> + 1

var elem1;
var elem2;
var elemListLength = elemList.length;

elem1 = elemList[Math.floor(Math.random() * elemListLength)];
if (elemListLength > 1) {
    do {
      elem2 = elemList[Math.floor(Math.random() * elemListLength)];
    } while(elem1 == elem2);
}

可以使用内置功能( slicesort )来完成,

var n = 2
    randomItems = array.sort(() => .5 - Math.random()).slice(0, n);

在 Rob W 告诉您的内容中,我要补充一点,另一种解决方案是找到一个随机点,并为第二个点找到与该点的随机偏移量:

var elem1;
var elem2;
var elemListLength = elemList.length;

var ix = Math.floor(Math.random() * elemListLength);
elem1 = elemList[ix];

if (elemListLength > 1) {
    elem2 = elemList[(ix + 1 + Math.floor(Math.random() * (elemListLength - 1))) % elemListLength];
}

我们加 1 是因为当前元素不能被重新选择,减 1 是因为已经选择了一个元素。

例如,一个包含三个元素 (0, 1, 2) 的数组。 我们随机选择元素 1。现在“好”偏移值是 0 和 1,偏移 0 给出元素 2,偏移 1 给出元素 0。

请注意,这将为您提供两个具有不同 INDEX 的随机元素,而不是具有不同 VALUE 的元素!

如果您想获得n随机元素,您可以创建列表的混洗版本,然后返回混洗数组的前n元素。

虽然洗牌数组并选择前两个是正确的。
您不需要打乱整个数组。

只需洗牌前两个!

var arrElm = [1, 2, 3, 4, 5, 6, 7]

var toTake = 2

var maxToShuffle = Math.min(arrElm.length - 1, toTake)

for (let i = 0; i < maxToShuffle; i++) {
  const toSwap = i + Math.floor(Math.random() * (arrElm.length - i))
  ;[arrElm[i], arrElm[toSwap]] = [arrElm[toSwap], arrElm[i]]
}

console.log(arrElm.slice(0, toTake))

https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle基本相同

除非你有足够的物品洗牌时提前退出。

你可以做一些像这样简单的事情

const elements = ['indie hackers', 'twitter', 'product hunt', 'linkedIn'];
const randomIndex = Math.floor(Math.random() * elements.length);
const a = elements[randomIndex];

const filteredElements = [...elements].splice(randomIndex, 1);
const b = filteredElements[Math.floor(Math.random() * elements.length)];

a 和 b 将是您的随机元素。

我发现这是最有用的技术之一:

var index1 = Math.floor(Math.random() * array.length);
var index2 = Math.floor(Math.random() * (array.length-1));
if index1 == index2 {
   index2 += 1;
}

您不能越界,因为 index2 无法获取最后一个元素。

如果您打乱数组并拼接要返回的元素数量,则返回值将包含尽可能多的项目,如果您要求的项目多于数组中的项目。 您可以使用 slice() 对实际数组或副本进行混洗。

Array.prototype.getRandom= function(num, cut){
    var A= cut? this:this.slice(0);
    A.sort(function(){
        return .5-Math.random();
    });
    return A.splice(0, num);
}
var a1= [1, 2, 3, 4, 5];
a1.getRandom(2)
>>[4, 2]

如果要从原始数组中删除所选项目,以便第二次调用不会包含第一次调用返回的元素,请传递第二个参数:getRandom(3,true);

window.Memry=window.Memry || {};
Memry.a1= [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

Memry.a1.getRandom(3,true);
>>[5,10,7]
Memry.a1.getRandom(3,true);
>>[3,9,6]
Memry.a1.getRandom(3,true);
>>[8,4,1]
Memry.a1.getRandom(3,true);
>>[2]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM