Computer >> 컴퓨터 >  >> 프로그래밍 >> JavaScript

JavaScript에서 리터럴 배열을 무작위로 섞는 방법

이 글에서는 리터럴 값으로 이루어진 배열을 받아, 그 요소들의 순서를 제자리(in-place)에서 무작위로 섞어주는 JavaScript 함수를 작성해 보겠습니다.

여기서 '제자리 섞기'란 새로운 배열을 생성하지 않고 원본 배열 자체의 순서를 직접 변경한다는 의미입니다.

구현 예제

해당 기능을 구현한 코드는 다음과 같습니다.

const letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
const unorderArray = arr => {
   let i, pos, temp;
   for (i = 0; i < 100; i++) {
      pos = Math.random() * arr.length | 0;
      temp = arr[pos];
      arr.splice(pos, 1);
      arr.push(temp);
   };
}
unorderArray(letters);
console.log(letters);

코드 동작 원리

  • Math.random() * arr.length | 0: 0 이상 배열 길이 미만 범위의 임의의 정수 인덱스를 생성합니다.
  • splice(pos, 1): 해당 인덱스에 있는 요소를 배열에서 제거합니다.
  • push(temp): 제거했던 요소를 배열의 맨 뒤에 다시 추가합니다.
  • 이 과정을 총 100회 반복하면서 배열의 순서가 점차 무작위로 뒤섞이게 됩니다.

실행 결과

콘솔에 출력되는 결과는 다음과 같습니다.

[
   'b', 'e', 'c',
   'a', 'g', 'f',
   'd'
]

위 출력은 가능한 여러 결과 중 하나일 뿐이라는 점에 유의하세요. 프로그램을 실행할 때마다 배열이 섞이는 순서는 매번 달라집니다.

참고: 피셔-예이츠(Fisher–Yates) 셔플

위 방식은 구현이 간단하지만, 반복 횟수와 추출 방식의 특성상 결과에 약간의 편향이 생길 수 있습니다. 모든 순열이 수학적으로 동일한 확률로 나오도록 보장하려면 피셔-예이츠 알고리즘을 사용하는 것이 좋습니다.

const fisherYatesShuffle = arr => {
   for (let i = arr.length - 1; i > 0; i--) {
      const j = Math.random() * (i + 1) | 0;
      [arr[i], arr[j]] = [arr[j], arr[i]];
   }
};
fisherYatesShuffle(letters);
console.log(letters);

피셔-예이츠 셔플은 배열의 끝에서부터 시작해 각 요소를 아직 결정되지 않은 앞쪽 요소 중 하나와 교환하는 방식으로, O(n)의 시간 복잡도로 균등하게 섞인 결과를 얻을 수 있습니다.