从数组中挑选2个随机元素
从数组中选择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
元素
不要使用循环和比较。 代替
- 洗牌arrays
- 先拿两个要素
当列表只包含一个项目时,您的代码将挂起。 而不是使用==
,我建议使用===
,在这种情况下看起来更合适。
另外,使用Math.floor
而不是Math.ceil
。 length
属性等于
。
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); }
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建议的那样。
关于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
元素。
如果您将数组洗牌并拼接要返回的元素数量,则返回值将包含尽可能多的项目,如果您要求的项目数多于数组中的项目数。 您可以使用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]
它可以使用内置function( 切片和排序 )来完成,
var n = 2 randomItems = array.sort(() => .5 - Math.random()).slice(0, n);