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

Javascript 从数组中选取2个随机元素,javascript,jquery,Javascript,Jquery,从一个数组中选择两个唯一的随机元素最有效的方法是什么(即,确保同一元素不会被选择两次) 到目前为止,我已经: var elem1; var elem2; elem1 = elemList[Math.ceil(Math.random() * elemList.length)]; do { elem2 = elemList[Math.ceil(Math.random() * elemList.length)]; } while(elem1 == elem2) 但这通常会挂起我的页面负载 有更

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

到目前为止,我已经:

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
元素当列表仅包含一项时,您的代码将挂起。我建议使用
===
,而不是使用
==
,这在本例中看起来更合适

另外,使用
Math.floor
代替
Math.ceil
length
属性等于
+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);
}

根据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


请注意,这将为您提供两个索引不同的随机元素,而不是不同的值

如果要获取
n
随机元素,可以创建列表的无序版本,然后返回无序数组的第一个
n
元素作为结果。

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

  • 阵列
  • 以前两个元素为例

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

如果要从原始阵列中删除选定项, 这样第二个调用就不会包含第一个调用返回的元素, 传递第二个参数:getRandom(3,true)

示例(列表,[n])

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


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

可以使用内置功能(和)


同时洗牌数组并选择前两个是正确的。
您不需要洗牌整个阵列

把前两个洗牌

var arrElm=[1,2,3,4,5,6,7]
var toTake=2
var maxthosuffle=Math.min(arrElm.length-1,toTake)
for(设i=0;i
基本上与


除非当你有足够多的物品被洗牌时,你就提前退出。

你可以做这样简单的事情

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将是您的随机元素。

当有多个元素时,我的代码将挂起,我将尝试使用您的代码。另外,有没有办法将其扩展到拾取
n
随机元素?@zsquare该代码和算法与此类似,这对于大型输入数组来说会更慢。@Dogbert:当然。另一方面,如果能确切地知道多大的阵列要慢多少,那将是一件有趣的事情。关注jsperf这个吗?我的数组相当大(500多个对象),正如@Dogbert所说的,这种方法效率不低吗?@zsquare:500个对象一点都不大。我认为不会有任何明显的区别。更重要的是,这种方法允许在固定时间内轻松拾取N个元素。@thg435说“500个对象一点也不大”就像说“500个字符串长度不是很长”。如果我有一个大数组,此方法是否仍比拾取n个随机元素快?这取决于与数组大小相关的n值。如果它们几乎相同,则洗牌可能会更快。我的数组是500多个元素,我需要2个元素:)与原始?@zsquare No-while循环相比,此方法有何优点。它将在恒定的确定时间内给出一对正确的元素。我认为它更优雅:-),但事实上没有什么真正重要的。在这种情况下,速度不是问题。但是有一个错误,
(elem1+1+Math.floor(Math.random()*(elemListLength-1))%elemListLength
elem1
是一个对象,您需要保存较旧的索引,而不是替代的索引
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]
_.sample([1, 2, 3, 4, 5, 6]);
=> 4

_.sample([1, 2, 3, 4, 5, 6], 3);
=> [1, 6, 2]
var n = 2
    randomItems = array.sort(() => .5 - Math.random()).slice(0, n);
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)];