21.02.23 TIL _.shuffle

J·2021년 2월 23일
0
_.shuffle = function (arr) { // arr 인자가 들어가는 shuffle 함수 표현식
  let arrCloned = arr.slice(); // arr 배열을 그대로 추출하는 arrCloned 를 선언
  for (let fromIdx = 0; fromIdx < arr.length; fromIdx++) { // fromIdx 변수는 0부터 시작하여 arr의 길이 직전만큼 1씩 증가한다.
    const toIdx = Math.floor(Math.random() * arr.length); // toIdx 는 (0~1 사이의 무작위의 수 * arr의 길이)에서 그 수와 같거나 넘지 않는 수를 할당한다.
    let temp = arrCloned[fromIdx]; // temp는 원본배열과 똑같은 arrCloned의 fromIdx번째 index에 해당함.
    arrCloned[fromIdx] = arrCloned[toIdx]; // 실질적으로 우리가 인지하는 shuffle 메소드가 이뤄지는 부분으로서, arrCloned의 fromIdx번째 요소는 toIdx번째 요소로 재할당된다.
    arrCloned[toIdx] = temp; // 재할당된 arrCloned[toIdx]는 temp로 다시 재할당된다. -> 이후 temp === arrCloned[toIdx] 이고, toIdx는 위의 선언에서 임의의 난수로 설정될 값이 있기 때문에 그 값이 정해져 있지 않다 -> 매 함수 실행시마다 바뀐 값을 갖게 된다. 
  }
  return arrCloned; // 재배열된 arrCloned 를 반환한다.
};

1. 개괄

shuffle이 무엇인가? 카드게임에서는 패 내지는 덱을 섞는 거고, 평소 우리가 쉽게 접하는 음악재생 부분에서는 무작위의 순서를 정하는 것을 말한다. _.shuffle 메소드 역시 실행방식을 보면 이 기능을 구현하는 것을 알 수 있다.

2. how it works?

_.shuffle 메소드는 먼저 배열을 인자로 잡은 후, 그것을 함수로 굴려야 한다. 기준이 되는 배열을 복사한 후(arrCloned), 그 복사된 배열의 요소(fromIdx)를 새로운 요소(toIdx)로 재할당해야 shuffle이 이루어진다.

실질적으로 우리가 인지하는 shuffle이 이루어지는 부분을 다시 보겠다.

let temp = arrCloned[fromIdx];
    arrCloned[fromIdx] = arrCloned[toIdx];
    arrCloned[toIdx] = temp;
  1. temp는 제일 처음(최초 함수 실행 전) 기준으로 원본과 같은 배열에 fromIdx번째 요소를 갖는다.
  2. 이후 temp는 원본 배열에 난수가 섞여 그 값이 무작위로 정해지는 toIdx번째 요소를 갖도록 재할당된다.
  3. 재할당된 temp는 이제 반복문이 실행(함수를 실행)될 때마다 새롭게 재할당된 요솟값을 갖게 된다.
    3-1. ex) temp = arrCloned[0];
    arrCloned[0] = arrCloned[8];
    arrCloned[8] = temp;
    이후 temp = arrCloned[8];
    arrCloned[8] = arrCloned[3];
    arrCloned[3] = temp;
    이후 temp = arrCloned[3]; ...............

3. Point

특히나 핵심이 되는 부분은 새로운 idx번째 요소를 할당하는 toIdx 부분. 이 부분에 Math.floor 및 Math.random 메소드를 써서, 배열의 모든 요소를 훑으면서 그 수가 무작위로 바뀌는 방식을 구현했다. 또한 arrCloned는 arr의 복제된 배열임을, fromIdx는 toIdx로 재할당되는 것을 나타냄을 보며 변수 이름을 잘 지어야 나도 그렇고 다른 사람들에게도 쉽게 이해가 됨을 다시금 느꼈다.

0개의 댓글