简体   繁体   English

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

[英]Picking 2 random elements from array

What is the most efficient way to select 2 unique random elements from an array (ie, make sure the same element is not selected twice).从数组中选择 2 个唯一随机元素的最有效方法是什么(即,确保同一元素未被选择两次)。

I have so far:我到目前为止:

var elem1;
var elem2;

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

But this often hangs my page load.但这经常挂起我的页面加载。

Any better solution?有更好的解决方案吗?

Extra question, how do I extend this to n elements额外的问题,我如何将其扩展到n元素

do NOT use loops and comparisons.不要使用循环和比较。 Instead反而

  • shuffle the array 打乱数组
  • take first two elements取前两个元素

http://underscorejs.org/#sample http://underscorejs.org/#sample

_.sample(list, [n]) _.sample(list, [n])

Produce a random sample from the list.从列表中生成一个随机样本。 Pass a number to return n random elements from the list.传递一个数字以从列表中返回 n 个随机元素。 Otherwise a single random item will be returned.否则将返回单个随机项目。

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

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

Looking at the source it uses shuffle just like @thg435 suggested.查看它使用shuffle的来源,就像@thg435 建议的那样。

Your code will hang when the list contains only one item.当列表仅包含一项时,您的代码将挂起。 Instead of using == , I recommend to use === , which looks more suitable in this case.我建议使用===而不是使用== ,这在这种情况下看起来更合适。

Also, use Math.floor instead of Math.ceil .另外,使用Math.floor而不是Math.ceil The length property is equal to <highest index> + 1 . 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);
}

It can be done using built-in functionality ( slice and sort ),可以使用内置功能( slicesort )来完成,

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

On what Rob W told you, I'll add that a different solution would be to find a random point and for the second point find a random offset from the point:在 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];
}

We add 1 because the current element can't be reselected and subtract 1 because one element has already been selected.我们加 1 是因为当前元素不能被重新选择,减 1 是因为已经选择了一个元素。

For example, an array of three elements (0, 1, 2).例如,一个包含三个元素 (0, 1, 2) 的数组。 We randomly select the element 1. Now the "good" offset value are 0 and 1, with offset 0 giving the element 2 and offset 1 giving the element 0.我们随机选择元素 1。现在“好”偏移值是 0 和 1,偏移 0 给出元素 2,偏移 1 给出元素 0。

Note that this will give you two random elements with different INDEX, not with different VALUE!请注意,这将为您提供两个具有不同 INDEX 的随机元素,而不是具有不同 VALUE 的元素!

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

While shuffle the array and pick the first two is correct.虽然洗牌数组并选择前两个是正确的。
You don't need to shuffle the whole array.您不需要打乱整个数组。

Just shuffle the first two!只需洗牌前两个!

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))

basically the same as https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shufflehttps://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle基本相同

Except you just quit early when you have enough item shuffled.除非你有足够的物品洗牌时提前退出。

You can do something easy like this你可以做一些像这样简单的事情

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 and b will be your random elements. a 和 b 将是您的随机元素。

I find this to be one of the most useful techniques:我发现这是最有用的技术之一:

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

You cannot go out of bounds as index2 cannot get the last element.您不能越界,因为 index2 无法获取最后一个元素。

If you shuffle the array and splice the number of elements you want to return, the return value will contain as many items as it can, if you ask for more items than are in the array.如果您打乱数组并拼接要返回的元素数量,则返回值将包含尽可能多的项目,如果您要求的项目多于数组中的项目。 You can shuffle the actual array or a copy, with slice().您可以使用 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]

If you want to remove the selected items from the original array, so that a second call will not include the elements the first call returned, pass a second argument: getRandom(3,true);如果要从原始数组中删除所选项目,以便第二次调用不会包含第一次调用返回的元素,请传递第二个参数: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