-
구현
1. 랜덤으로 뽑고 중복체크
/** * 중복 없이 랜덤으로 숫자 뽑기 * @param {Number} min 최소 숫자 * @param {Number} max 최대 숫자 * @param {Number} count 뽑을 개수 * @returns {Number[]} 중복 없는 랜덤 숫자 배열 */ function getUniqueRandomNums(min, max, count) { const result = []; const rangeCount = max - min + 1; let r; while (result.length < count) { r = Math.floor(Math.random() * rangeCount + min); if (result.includes(r) == false) { result.push(r); } } return result; }
코드가 간결하지만 일단 랜덤으로 뽑은 후
배열을 순회해서 중복 체크를 하기 때문에
중복 없이 뽑을 확률이 낮을수록 오래 걸립니다.최소 연산 횟수는
(count + 1) * count / 2
라서
min, max 범위는 넓고 뽑을 개수 count가 적다면
대부분은 빠르게 실행됩니다.2. 배열에 넣고 랜덤으로 뽑기
/** * 중복 없이 랜덤으로 숫자 뽑기 * @param {Number} min 최소 숫자 * @param {Number} max 최대 숫자 * @param {Number} count 뽑을 개수 * @returns {Number[]} 중복 없는 랜덤 숫자 배열 */ function getUniqueRandomNums(min, max, count) { const nums = []; const result = []; let rangeCount = max - min + 1; // min부터 max까지 nums배열에 넣음 for (let i = 0; i < rangeCount; i++) { nums[i] = i + min; } // 중복없이 랜덤으로 count만큼 뽑음 for (let i = 0, r; i < count; i++) { r = Math.floor(Math.random() * --rangeCount); result[i] = nums[r]; nums[r] = nums[rangeCount]; } return result; }
배열에 min, max 범위만큼 넣어놓고
랜덤으로 고른 후, 제외하기 때문에
연산 횟수는 확률에 의존하지 않아서max - min + count + 1
고정입니다.O(n)
이라 빠를 거 같아 보이지만
min, max 범위가 넓으면 넓을수록
배열에 넣는 과정에서 고정 횟수가 있기 때문에
범위가 넓지 않을수록 빠릅니다.예제
로또 번호를 뽑고자 하면
최소 번호: 1
최대 번호: 45
뽑을 개수: 6getUniqueRandomNums(1, 45, 6);
콘솔에 출력하면 아래와 같이 나옵니다.
[19, 1, 36, 40, 10, 4]
getUniqueRandomNums(1, 45, 6).sort((a, b) => a - b);
sort 메서드를 통해 낮은 순으로 정렬하면
[1, 4, 10, 19, 36, 40]
이렇게 됩니다.댓글