underscore 라이브러리의 많은 기능 중에서도, shuffle이라는 라이브러리가 있다.
우선 shuffle의 사전적 의미는 '발을 끌며 걷다', '뒤 섞다'등의 뜻이 있는데,
그렇다면 shuffle 라이브러리의 기능은 무언가
'여러개의 요소들을 뒤섞어서 랜덤하게 값을 나타내주는 역할'을 해주지않을까?
말 그대로 shuffle은, '배열의 element들을 무작위로 섞은 뒤, 섞은 배열을 리턴'해주는 기능을 갖고있다.
오늘은 이 라이브러리를 조금씩 파헤쳐보면서 어떻게 작동되는 원리인건지 알아보도록 하겠다.
그러므로
let arrCloned = arr.slice();
원래는 아예 한 변수에, Math.random()의 값을 arr.length와 곱하여 Math.floor()를 한번에 적용시키는게 빠르겠지만,
각각 어떤 값이 들어오는지 일일이 확인하여 그 과정을 확인하려 한다!
그러므로 우선, for문은 array의 길이만큼 돌면서,
먼저 Math.random()함수를 이용해 0 이상 1 미만의 수 중 랜덤한 소수를 하나 가져온다.
for(let i=0;i<arr.length;i++){
let random = Math.random();
..
만약 처음에, 예를들어 0.8909277722120477 라는 수가 찍힌다고 가정해보자.
arr의 길이는 총 6이므로 둘을 곱하면 5.345566633272286 라는 수가 나온다.
왜냐하면 기본적으로
Math.random()함수에 어떤 특정 정수를 곱할시에, 무조건 그 정수 미만의 수가 나오기때문이다.
이는 여러번 그 값을 호출하더라도 무조건 그 범위안의 수만 나오는 식이기 때문에, 기본적으로 외워두면 좋다.
자바에서도 마찬가지였다. 자바도 똑같은 Math객체의 메소드들이 마련되어있는데, 작동방식이 같아서 그대로 이해할 수 있었다.
let r = random*arr.length;
let toIdx = Math.floor(r);
[1, 2, 34, 56, 7, 8]
그리고, 임시로 저장할 변수인 temp에 arrCLoned의 0번째 요소인 1을 가져와서 저장해놓는다.
let temp = arrCloned[i];
arrCloned[i] = arrCloned[r];
arrCloned[r] = temp;
이제 for문이 모두 종료가 될때까지 랜덤한 수에 arr.length를 곱하고..
그 랜덤한 인덱스값을 또 임시저장방 temp에 집어넣고..
빈 arr의 공간에 랜덤 인덱스의 공간값을 집어넣고..
빈 랜덤인덱스의 공간에 temp의 값을 집어넣고....
계속 반복하여 두 공간씩 자리를 바꿔준다고 생각하면 된다!! 😋😋
그러면 최종적으로 나온 랜덤이 적용된 배열의 각 요소들은,
좀 더 한눈에 파악하기 쉽게 각 과정들 몇 개를 정리해보았다.
let temp = arrCloned[i] // temp = 1
arrCloned[i] = arrCloned[toIdx]; // arrCloned[0] = 8
arrCloned[toIdx] = temp; //arrCloned[5] = 1;
//arrCloned: (6) [8, 2, 34, 56, 7, 1]
//random: 0.8909277722120477
//r: 4.680967397053604
//toIdx: 4
let temp = arrCloned[i] // temp = 2
arrCloned[i] = arrCloned[toIdx]; // arrCloned[1] = 7
arrCloned[toIdx] = temp; //arrCloned[4] = 2;
//arrCloned: (6) [8, 7, 34, 56, 2, 1]
//random: 0.8730173096217597
//r: 5.238103857730558
//toIdx: 5
let temp = arrCloned[i] // temp = 34
arrCloned[i] = arrCloned[toIdx]; // arrCloned[2] = 8
arrCloned[toIdx] = temp; //arrCloned[5] = 34;
//arrCloned: (6) [8, 7, 1, 56, 2, 34] < 이렇게 i를 사용하는 인덱스의 방은 순차적으로 값이 바뀔테지만,
//랜덤코드에 의해 바뀔 상대의 공간은, 이렇게 처음 과정에서 한번 바뀜당한 곳(arrCloned[5])인데도 또 안의 값이 바뀌는것을 볼 수 있다. 이번엔 34로 바뀌었다.
.
.
.
해서 최종적으로 셔플된 결과는
가 나온것을 볼 수 있다.
최종 레퍼런스 코드
function shuffle(arr){ let arrCloned = arr.slice(); for(let i=0;i<arr.length;i++){ let random = Math.random(); let r = random*arr.length; let toIdx = Math.floor(r); //let toIdx = Math.floor(Math.random()*arr.length); let temp = arrCloned[i]; arrCloned[i] = arrCloned[r]; arrCloned[r] = temp; } return arrCloned; } let result = shuffle([1,2,34,56,7,8]); console.log(result);
그렇다면 이 shuffle메소드는 대체, 어떤때에 활용할 수 있을까?
랜덤한 여러 개의 수들을 사용하여, 어떤 특정한 때에 그 랜덤수들은 마치, '어떤 특별한 키, 즉, 식별번호'처럼 사용할 수 있지 않을까?
해서 나는, '로또'가 이런 원리로 수를 랜덤하게 섞어서 행운의 번호를 만드는것이 아닐까 생각했다.
기본 6개의 수가 들어갈 배열을 하나 선언해놓고, 중복을 거르는 조건을 만들어서 배열의 i번째에 순차적으로 넣을 수 있다면..?
아니면 특정 식별번호인 택배 주문번호 라던가, 구글의 백업 키, 자동 비밀번호 생성 등에도 사용할 수 있을것같다!!
이번에 연습해서 로또 생성 프로그램을 꼭 만들어봐야겠다.
후기
내가 자바를 배우지 않았다면 random()함수의 이해가 어려웠을것 같은데, 그때 미친척 엄청 연습해놔서 다행이었다.... 잊지말자. 나는 남들보다 배는 노력해야한다. 이게 끝이 아니다. 화이팅.