배열에서 여러 임의의 요소를 얻는 방법은 무엇입니까?


104

나는 '자바 스크립트의 배열에서 무작위로 요소에 액세스하는 방법'을 연구하고 있습니다. 이것에 관한 많은 링크를 찾았습니다. 좋아요 : JavaScript 배열에서 임의의 항목 가져 오기

var item = items[Math.floor(Math.random()*items.length)];

그러나 여기에서는 배열에서 하나의 항목 만 선택할 수 있습니다. 둘 이상의 요소를 원하면 어떻게 이것을 달성 할 수 있습니까? 배열에서 하나 이상의 요소를 어떻게 얻을 수 있습니까?


5
여러 번 실행 하시겠습니까?
Bergi

2
이 진술에서 우리는 이것을 할 수 있습니까 ?? 중복을 생성하는 루프.
Shyam Dixit 2013 년

1
정확한 진술에서 당신은 하나 이상의 요소를 얻을 수 없습니다.
Sébastien 2013 년

1
아, 당신은 중복을 원하지 않는다고 말 했어야했습니다. 그런 다음 O (1)에서 고유 한 난수를 확인 하시겠습니까? 그리고 중복을 방지하기 위해 기록을 유지하는 범위 내 고유 번호 생성 (0-X)
Bergi

1
여기에서 일부 솔루션을 테스트하기 위해 JsPerf를 만들었습니다. @Bergi는 일반적으로 최고인 것 같지만 배열에서 많은 요소가 필요한 경우 내 것이 더 잘 작동합니다. jsperf.com/k-random-elements-from-array
Tibos 2013-10-09

답변:


101

다음과 같은 비파괴 ( 빠른 ) 기능을 사용해보십시오 .

function getRandom(arr, n) {
    var result = new Array(n),
        len = arr.length,
        taken = new Array(len);
    if (n > len)
        throw new RangeError("getRandom: more elements taken than available");
    while (n--) {
        var x = Math.floor(Math.random() * len);
        result[n] = arr[x in taken ? taken[x] : x];
        taken[x] = --len in taken ? taken[len] : len;
    }
    return result;
}

10
이 알고리즘의 아름다움을 감상하는데 약 10 분을 보냈다고 말하고 싶었습니다.
Prajeeth Emanuel 2017-04-08

속도를 원한다면 Python의 구현을 사용하는 것이 좋습니다 . jsperf.com/pick-random-elements-from-an-array
Derek 朕 會 功夫

@Derek 朕 會 功夫 아, 영리합니다. 실제로 큰 범위의 작은 샘플에 훨씬 더 효과적입니다. 특히 ES6를 사용하는 경우 Set('13 :-/에서는 사용할 수 없었 음)
Bergi

@AlexWhite 피드백 주셔서 감사합니다.이 버그가 수년 동안 모든 사람을 피했다는 사실을 믿을 수 없습니다. 결정된. 하지만 편집을 제안하지 말고 댓글을 게시 했어야합니다.
Bergi

2
@ cbdev420 예, 그것은 (부분) 피셔 - 예이츠 셔플 단지
BERGI

191

두 줄 :

// Shuffle array
const shuffled = array.sort(() => 0.5 - Math.random());

// Get sub-array of first n elements after shuffled
let selected = shuffled.slice(0, n);

데모 :


22
아주 좋아요! 물론 하나의 라이너도 가능합니다 :let random = array.sort(() => .5 - Math.random()).slice(0,n)
unitario

1
천재! 내장 기능을 사용하여 우아하고 짧고 간단하며 빠릅니다.
Vlad

36
좋지만 무작위와는 거리가 멀다. 첫 번째 항목은 마지막 항목보다 선택 될 가능성이 더 많습니다. 이유는 여기에서 확인하세요 : stackoverflow.com/a/18650169/1325646
pomber

이것은 원래 배열의 종류를 보존하지 않습니다
almathie

3
놀랄 만한! 배열을 그대로 유지하려면 다음과 같이 첫 번째 줄을 변경하면됩니다. const shuffled = [... array] .sort (() => 0.5-Math.random ());
Yair Levy


12

.samplePython 표준 라이브러리에서 포팅 :

function sample(population, k){
    /*
        Chooses k unique random elements from a population sequence or set.

        Returns a new list containing elements from the population while
        leaving the original population unchanged.  The resulting list is
        in selection order so that all sub-slices will also be valid random
        samples.  This allows raffle winners (the sample) to be partitioned
        into grand prize and second place winners (the subslices).

        Members of the population need not be hashable or unique.  If the
        population contains repeats, then each occurrence is a possible
        selection in the sample.

        To choose a sample in a range of integers, use range as an argument.
        This is especially fast and space efficient for sampling from a
        large population:   sample(range(10000000), 60)

        Sampling without replacement entails tracking either potential
        selections (the pool) in a list or previous selections in a set.

        When the number of selections is small compared to the
        population, then tracking selections is efficient, requiring
        only a small set and an occasional reselection.  For
        a larger number of selections, the pool tracking method is
        preferred since the list takes less space than the
        set and it doesn't suffer from frequent reselections.
    */

    if(!Array.isArray(population))
        throw new TypeError("Population must be an array.");
    var n = population.length;
    if(k < 0 || k > n)
        throw new RangeError("Sample larger than population or is negative");

    var result = new Array(k);
    var setsize = 21;   // size of a small set minus size of an empty list

    if(k > 5)
        setsize += Math.pow(4, Math.ceil(Math.log(k * 3) / Math.log(4)))

    if(n <= setsize){
        // An n-length list is smaller than a k-length set
        var pool = population.slice();
        for(var i = 0; i < k; i++){          // invariant:  non-selected at [0,n-i)
            var j = Math.random() * (n - i) | 0;
            result[i] = pool[j];
            pool[j] = pool[n - i - 1];       // move non-selected item into vacancy
        }
    }else{
        var selected = new Set();
        for(var i = 0; i < k; i++){
            var j = Math.random() * n | 0;
            while(selected.has(j)){
                j = Math.random() * n | 0;
            }
            selected.add(j);
            result[i] = population[j];
        }
    }

    return result;
}

Lib / random.py 에서 이식 된 구현 입니다.

메모:

  • setsize효율성을 위해 Python의 특성을 기반으로 설정됩니다. JavaScript에 맞게 조정되지 않았지만 알고리즘은 여전히 ​​예상대로 작동합니다.
  • 이 페이지에 설명 된 일부 다른 답변은 Array.prototype.sort. 그러나이 알고리즘은 한정된 시간 내에 종료됩니다.
  • 하지 않는 이전 브라우저의 Set구현, 설정은로 대체 할 수 Array.has(j)교체 .indexOf(j) > -1.

허용 된 답변에 대한 성능 :


아래에이 코드 의 최적화 된 버전 을 게시했습니다 . 또한 게시물의 두 번째 알고리즘에서 잘못된 임의 매개 변수를 수정했습니다. 얼마나 많은 사람들이 프로덕션에서 이전 편향 버전을 사용하고 있는지 궁금합니다.
사용자

11

원래 배열을 변경하지 않고 무작위 항목 5 개 얻기 :

const n = 5;
const sample = items
  .map(x => ({ x, r: Math.random() }))
  .sort((a, b) => a.r - b.r)
  .map(a => a.x)
  .slice(0, n);

(큰 목록에는 사용하지 마십시오)


이것이 어떻게 작동하는지 더 잘 설명 할 수 있을까요?
Qasim

10

다음과 같은 기능을 만듭니다.

var getMeRandomElements = function(sourceArray, neededElements) {
    var result = [];
    for (var i = 0; i < neededElements; i++) {
        result.push(sourceArray[Math.floor(Math.random()*sourceArray.length)]);
    }
    return result;
}

또한 sourceArray에 반환 할 요소가 충분한 지 확인해야합니다. 고유 한 요소를 반환하려면 sourceArray에서 선택한 요소를 제거해야합니다.


좋은 대답입니다! 내 대답을 살펴보고 코드를 복사하고 "유일한 요소 만"기능을 추가했습니다.
evilReiko

1
이 함수는 동일한 요소를 sourceArray여러 번 반환 할 수 있습니다 .
Sampo

6

ES6 구문

const pickRandom = (arr,count) => {
  let _arr = [...arr];
  return[...Array(count)].map( ()=> _arr.splice(Math.floor(Math.random() * _arr.length), 1)[0] ); 
}

5

반복하지 않고 루프에서 배열에서 항목을 무작위로 가져 오려면 다음을 사용하여 배열에서 선택한 항목을 제거 할 수 있습니다 splice.

var items = [1, 2, 3, 4, 5];
var newItems = [];

for (var i = 0; i < 3; i++) {
  var idx = Math.floor(Math.random() * items.length);
  newItems.push(items[idx]);
  items.splice(idx, 1);
}

console.log(newItems);


1
문 items.splice (idx, 1)에서 왜이 '1'을 사용합니까? 접착??
Shyam Dixit 2013 년

2
샴 딕 시트는 상기에 따른 MDN 문서1deleteCount제거 이전 배열 요소의 수를 나타낸다. (실수로 마지막 두 줄을 newItems.push(items.splice(idx, 1)[0]))로 줄 였습니다.
Kurt Peek

4

lodash ( https://lodash.com/ ) _.sample_.sampleSize.

컬렉션에서 컬렉션 크기까지의 고유 키에서 하나 또는 n 개의 임의 요소를 가져옵니다.

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

_.sampleSize([1, 2, 3], 2);
// => [3, 1]
 
_.sampleSize([1, 2, 3], 3);
// => [2, 3, 1]

무엇입니까 _? 표준 Javascript 객체가 아닙니다.
vanowm

안녕하세요 @vanowm, lodash lodash.com
nodejh

2
Array.prototype.getnkill = function() {
    var a = Math.floor(Math.random()*this.length);
    var dead = this[a];
    this.splice(a,1);
    return dead;
}

//.getnkill() removes element in the array 
//so if you like you can keep a copy of the array first:

//var original= items.slice(0); 


var item = items.getnkill();

var anotheritem = items.getnkill();

2

여기에 잘 입력 된 버전이 있습니다. 실패하지 않습니다. 샘플 크기가 원래 배열의 길이보다 큰 경우 셔플 된 배열을 반환합니다.

function sampleArr<T>(arr: T[], size: number): T[] {
  const setOfIndexes = new Set<number>();
  while (setOfIndexes.size < size && setOfIndexes.size < arr.length) {
    setOfIndexes.add(randomIntFromInterval(0, arr.length - 1));
  }
  return Array.from(setOfIndexes.values()).map(i => arr[i]);
}

const randomIntFromInterval = (min: number, max: number): number =>
  Math.floor(Math.random() * (max - min + 1) + min);

2

2020
비파괴 함수 프로그래밍 스타일, 변경 불가능한 컨텍스트에서 작동합니다.

const _randomslice = (ar, size) => {
  let new_ar = [...ar];
  new_ar.splice(Math.floor(Math.random()*ar.length),1);
  return ar.length <= (size+1) ? new_ar : _randomslice(new_ar, size);
}


console.log(_randomslice([1,2,3,4,5],2));


함수가 소스 배열에서 가능한 모든 임의 배열을 생성하지 않는다는 것을 알고 있습니다. 다른 세계에서는 결과가 예상대로 무작위가 아닙니다. 개선 할 생각이 있습니까?
MAMY Sébastien

_shuffle기능 은 어디에 있습니까?
vanowm

1

편집 :이 솔루션은 몇 가지 요소 만 얻으려는 경우 여기에 제시된 다른 솔루션 (소스 배열을 연결)보다 느립니다. 이 솔루션의 속도는 원래 배열의 요소 수에만 의존하는 반면 스 플라이 싱 솔루션의 속도는 출력 배열에 필요한 요소의 수에 따라 다릅니다.

반복되지 않는 임의의 요소를 원한다면 배열을 섞은 다음 원하는만큼만 얻을 수 있습니다.

function shuffle(array) {
    var counter = array.length, temp, index;

    // While there are elements in the array
    while (counter--) {
        // Pick a random index
        index = (Math.random() * counter) | 0;

        // And swap the last element with it
        temp = array[counter];
        array[counter] = array[index];
        array[index] = temp;
    }

    return array;
}

var arr = [0,1,2,3,4,5,7,8,9];

var randoms = shuffle(arr.slice(0)); // array is cloned so it won't be destroyed
randoms.length = 4; // get 4 random elements

데모 : http://jsbin.com/UHUHuqi/1/edit

여기에서 가져온 셔플 기능 : https://stackoverflow.com/a/6274398/1669279


이는 어레이에서 필요한 임의 항목의 비율에 따라 다릅니다. 10 개의 요소 배열에서 9 개의 임의의 요소를 원하는 경우 9 개의 임의의 요소를 차례로 추출하는 것보다 셔플하는 것이 확실히 더 빠릅니다. 이것이 유용한 백분율이 50 % 미만이면이 솔루션이 가장 빠른 사용 사례가 있습니다. 그렇지 않으면 쓸모 없다는 것을 인정합니다. :).
Tibos 2013 년

9 개의 요소를 섞는 것이 10 개의 요소를 섞는 것보다 빠르다는 것을 의미했습니다. Btw 나는 OP가 그의 입력 배열을 파괴하고 싶지 않다고 확신합니다…
Bergi

9 가지 요소를 섞는 것이이 문제에서 어떻게 도움이되는지 이해하지 못한다고 생각합니다. 배열의 절반 이상을 원하는 경우 원하는 수로 남아있을 때까지 임의의 요소를 슬라이스 아웃 한 다음 임의 순서를 얻기 위해 셔플 할 수 있다는 것을 알고 있습니다. 내가 놓친 것이 있습니까? 추신 : 고정 어레이 파괴, 감사합니다.
Tibos 2013 년

"half of"로 아무것도 할 필요가 없습니다. 되돌리고 싶은 요소만큼 많은 작업을 수행하면되며, 어느 시점에서든 전체 배열을 처리 할 필요가 없습니다. 현재 코드의 복잡성은 O(n+k)(배열의 n 요소, 원하는 요소 k) O(k)가능 하지만 최적입니다.
Bergi

1
좋아, 당신의 코드는 루프를 변경 하고 마지막 (첫 번째 대신) 요소를 빼 내면 O(2n)줄일 수있는 것과 비슷 합니다. 실제로 이없는 ,하지만 솔루션은 (내 대답을 참조) 여전히 가능하다. 그러나 공간 복잡성은 불행히도 유지 되지만 희소 배열 구현에 따라 달라질 수 있습니다. O(n+k)while (counter-- > len-k)ksplice(i, 1)O(1)O(k)O(n+k)O(2k)
Bergi

1

이런 종류의 문제를 해결하는 기능이 필요했기 때문에 여기서 공유하겠습니다.

    const getRandomItem = function(arr) {
        return arr[Math.floor(Math.random() * arr.length)];
    }

    // original array
    let arr = [4, 3, 1, 6, 9, 8, 5];

    // number of random elements to get from arr
    let n = 4;

    let count = 0;
    // new array to push random item in
    let randomItems = []
    do {
        let item = getRandomItem(arr);
        randomItems.push(item);
        // update the original array and remove the recently pushed item
        arr.splice(arr.indexOf(item), 1);
        count++;
    } while(count < n);

    console.log(randomItems);
    console.log(arr);

참고 : n = arr.length기본적으로 배열을 셔플하고 셔플 된 배열 arrrandomItems반환합니다.

데모


1

이 답변에서는 모든 요소가 임의의 하위 배열을 가질 수있는 동일한 기회를 제공하는 최상의 방법을 알아야한다는 테스트를 여러분과 공유하고 싶습니다.

방법 01

array.sort(() => Math.random() - Math.random()).slice(0, n)

이 방법을 사용하면 일부 요소는 다른 요소에 비해 더 높은 가능성을 갖습니다.

calculateProbability = function(number=0 ,iterations=10000,arraySize=100) { 
let occ = 0 
for (let index = 0; index < iterations; index++) {
   const myArray= Array.from(Array(arraySize).keys()) //=> [0, 1, 2, 3, 4, ... arraySize]
   
  /** Wrong Method */
    const arr = myArray.sort(function() {
     return val= .5 - Math.random();
      });
     
  if(arr[0]===number) {
    occ ++
    }

    
}

console.log("Probability of ",number, " = ",occ*100 /iterations,"%")

}

calculateProbability(0)
calculateProbability(0)
calculateProbability(0)
calculateProbability(50)
calculateProbability(50)
calculateProbability(50)
calculateProbability(25)
calculateProbability(25)
calculateProbability(25)

방법 2

이 방법을 사용하면 요소의 확률이 동일합니다.

 const arr = myArray
      .map((a) => ({sort: Math.random(), value: a}))
      .sort((a, b) => a.sort - b.sort)
      .map((a) => a.value)

calculateProbability = function(number=0 ,iterations=10000,arraySize=100) { 
let occ = 0 
for (let index = 0; index < iterations; index++) {
   const myArray= Array.from(Array(arraySize).keys()) //=> [0, 1, 2, 3, 4, ... arraySize]
   

  /** Correct Method */
  const arr = myArray
  .map((a) => ({sort: Math.random(), value: a}))
  .sort((a, b) => a.sort - b.sort)
  .map((a) => a.value)
    
  if(arr[0]===number) {
    occ ++
    }

    
}

console.log("Probability of ",number, " = ",occ*100 /iterations,"%")

}

calculateProbability(0)
calculateProbability(0)
calculateProbability(0)
calculateProbability(50)
calculateProbability(50)
calculateProbability(50)
calculateProbability(25)
calculateProbability(25)
calculateProbability(25)

정답은 다음 링크에 게시되어 있습니다. https://stackoverflow.com/a/46545530/3811640


1

다음 은 @Derek이 Python에서 이식 한 코드 의 최적화 된 버전이며, 가능한 한 가장 빠른 알고리즘을 가능하게하는 파괴적 (내부) 옵션이 추가되었습니다. 그렇지 않으면 전체 복사본을 만들거나 큰 배열에서 요청 된 적은 수의 항목에 대해 선택 기반 알고리즘으로 전환합니다.

// Chooses k unique random elements from pool.
function sample(pool, k, destructive) {
    var n = pool.length;
    
    if (k < 0 || k > n)
        throw new RangeError("Sample larger than population or is negative");
    
    if (destructive || n <= (k <= 5 ? 21 : 21 + Math.pow(4, Math.ceil(Math.log(k*3) / Math.log(4))))) {
        if (!destructive)
            pool = Array.prototype.slice.call(pool);
        for (var i = 0; i < k; i++) { // invariant: non-selected at [i,n)
            var j = i + Math.random() * (n - i) | 0;
            var x = pool[i];
            pool[i] = pool[j];
            pool[j] = x;
        }
        pool.length = k; // truncate
        return pool;
    } else {
        var selected = new Set();
        while (selected.add(Math.random() * n | 0).size < k) {}
        return Array.prototype.map.call(selected, i => population[i]);
    }
}

Derek의 구현과 비교할 때 첫 번째 알고리즘은 Firefox에서 훨씬 빠르지 만 Chrome에서는 약간 느리지 만 이제는 파괴적인 옵션 (가장 성능이 뛰어난 옵션)이 있습니다. 두 번째 알고리즘은 5-15 % 더 빠릅니다. k와 n에 따라 다르기 때문에 구체적인 숫자를 제공하지 않으려 고 노력하며 새 브라우저 버전에서는 앞으로 아무 의미가 없을 것입니다.

알고리즘을 선택하는 휴리스틱은 Python 코드에서 비롯됩니다. 때때로 느린 것을 선택하지만 나는 그대로 두었습니다. JS에 최적화되어야하지만 코너 케이스의 성능이 브라우저와 버전에 따라 다르기 때문에 복잡한 작업입니다. 예를 들어 1000 또는 1050 중 20 개를 선택하려고하면 그에 따라 첫 번째 또는 두 번째 알고리즘으로 전환됩니다. 이 경우 첫 번째는 Chrome 80에서 두 번째 것보다 2 배 빠르게 실행되지만 Firefox 74에서는 3 배 느립니다.


log(k*3, 4)JS에 base인수 가 없기 때문에 오류가 있습니다 . 되어야합니다log(k*3)/log(4)
disfated

또한, 나는 당신이 다시 부분에서 단점을 볼 poolA와 result. 자르기 때문에 pool더 이상 샘플링을위한 소스로 사용할 수 없으며 다음에 사용할 samplepool일부 소스에서 다시 만들어야 합니다. Derek의 구현은 풀을 섞기 만하므로 다시 만들지 않고도 샘플링에 완벽하게 재사용 할 수 있습니다. 그리고 이것이 가장 빈번한 사용 사례라고 생각합니다.
disfated

@disfated, 감사 log합니다. 저와 Derek의 코드에서 수정 되었습니다. 를 재사용하려면 옵션을 pool활성화하지 마십시오 destructive. 그러면 pool인수가 복사본으로 숨겨집니다.
사용자

0

srcArray에서 무작위 요소를 하나씩 추출하는 동안 충분하거나 추출 할 srcArray에 더 이상 요소가 없습니다. 빠르고 안정적입니다.

function getNRandomValuesFromArray(srcArr, n) {
    // making copy to do not affect original srcArray
    srcArr = srcArr.slice();
    resultArr = [];
    // while srcArray isn't empty AND we didn't enough random elements
    while (srcArr.length && resultArr.length < n) {
        // remove one element from random position and add this element to the result array
        resultArr = resultArr.concat( // merge arrays
            srcArr.splice( // extract one random element
                Math.floor(Math.random() * srcArr.length),
                1
            )
        );
    }

    return resultArr;
}


SO에 오신 것을 환영합니다! 답변을 게시 할 때 코드 작동 방식 및 / 또는 OP 문제 해결 방법을 언급하는 것이 중요합니다. :)
Joel

0

2019 년

이것은 Laurynas Mališauskas의 대답 과 동일하지만 요소가 고유하다는 점만 있습니다 (중복 없음).

var getMeRandomElements = function(sourceArray, neededElements) {
    var result = [];
    for (var i = 0; i < neededElements; i++) {
    var index = Math.floor(Math.random() * sourceArray.length);
        result.push(sourceArray[index]);
        sourceArray.splice(index, 1);
    }
    return result;
}

이제 "jQuery로 여러 임의의 요소를 얻는 방법"이라는 원래 질문에 답하려면 다음을 수행하십시오.

var getMeRandomElements = function(sourceArray, neededElements) {
    var result = [];
    for (var i = 0; i < neededElements; i++) {
    var index = Math.floor(Math.random() * sourceArray.length);
        result.push(sourceArray[index]);
        sourceArray.splice(index, 1);
    }
    return result;
}

var $set = $('.someClass');// <<<<< change this please

var allIndexes = [];
for(var i = 0; i < $set.length; ++i) {
    allIndexes.push(i);
}

var totalRandom = 4;// <<<<< change this please
var randomIndexes = getMeRandomElements(allIndexes, totalRandom);

var $randomElements = null;
for(var i = 0; i < randomIndexes.length; ++i) {
    var randomIndex = randomIndexes[i];
    if($randomElements === null) {
        $randomElements = $set.eq(randomIndex);
    } else {
        $randomElements.add($set.eq(randomIndex));
    }
}

// $randomElements is ready
$randomElements.css('backgroundColor', 'red');

0

다음은 교체 여부에 관계없이 배열을 쉽게 샘플링 할 수있는 함수입니다.

  // Returns a random sample (either with or without replacement) from an array
  const randomSample = (arr, k, withReplacement = false) => {
    let sample;
    if (withReplacement === true) {  // sample with replacement
      sample = Array.from({length: k}, () => arr[Math.floor(Math.random() *  arr.length)]);
    } else { // sample without replacement
      if (k > arr.length) {
        throw new RangeError('Sample size must be less than or equal to array length         when sampling without replacement.')
      }
      sample = arr.map(a => [a, Math.random()]).sort((a, b) => {
        return a[1] < b[1] ? -1 : 1;}).slice(0, k).map(a => a[0]); 
      };
    return sample;
  };

사용은 간단합니다.

대체하지 않음 (기본 동작)

randomSample([1, 2, 3], 2) 돌아올 수있다 [2, 1]

교체 포함

randomSample([1, 2, 3, 4, 5, 6], 4) 돌아올 수있다 [2, 3, 3, 2]


0
var getRandomElements = function(sourceArray, requiredLength) {
    var result = [];
    while(result.length<requiredLength){
        random = Math.floor(Math.random()*sourceArray.length);
        if(result.indexOf(sourceArray[random])==-1){
            result.push(sourceArray[random]);
        }
    }
    return result;
}

0

나는 아무도이 방법을 언급하지 않았다는 것을 믿을 수 없다. 꽤 깨끗하고 솔직하다.

const getRnd = (a, n) => new Array(n).fill(null).map(() => a[Math.floor(Math.random() * a.length)]);

두 항목이 반복되지 않는지 확인하지 않습니다.
Valery

-2

여기에 가장 정답이 있으며 Random + Unique 요소를 제공합니다.

function randomize(array, n)
{
    var final = [];
    array = array.filter(function(elem, index, self) {
        return index == self.indexOf(elem);
    }).sort(function() { return 0.5 - Math.random() });

    var len = array.length,
    n = n > len ? len : n;

    for(var i = 0; i < n; i ++)
    {
        final[i] = array[i];
    }

    return final;
}

// randomize([1,2,3,4,5,3,2], 4);
// Result: [1, 2, 3, 5] // Something like this

이 무작위 화에 이상한 일이 벌어지고 있습니다. 동일한 결과가 9 번 중 6 번 시도했습니다 (n은 8이고 배열 크기는 148입니다). Fisher-Yates 방법으로 전환하는 것에 대해 생각할 수 있습니다 . 내가 한 일이고 지금은 훨씬 더 잘 작동합니다.
asetniop

이것은 잘못된 고유성 검사를 수행하고 무작위 비교로 정렬되기 때문에 모든 항목을 선택할 기회가 같지 않기 때문에 2 차 시간이 걸립니다.
Ry-

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.