Picking 2 random elements from array

前端 未结 9 891
一向
一向 2020-12-16 18:32

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

I have so far:



        
相关标签:
9条回答
  • 2020-12-16 19:10

    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. The length property is equal to <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);
    }
    
    0 讨论(0)
  • 2020-12-16 19:11

    do NOT use loops and comparisons. Instead

    • shuffle the array
    • take first two elements
    0 讨论(0)
  • 2020-12-16 19:18

    http://underscorejs.org/#sample

    _.sample(list, [n])

    Produce a random sample from the list. Pass a number to return n random elements from the list. 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.

    0 讨论(0)
  • 2020-12-16 19:18

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

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

    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]
    
    0 讨论(0)
  • 2020-12-16 19:25

    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:

    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.

    For example, an array of three elements (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.

    Note that this will give you two random elements with different INDEX, not with different VALUE!

    0 讨论(0)
  • 2020-12-16 19:27

    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_shuffle

    Except you just quit early when you have enough item shuffled.

    0 讨论(0)
提交回复
热议问题