• 로또, 중복없이 랜덤으로 숫자 뽑기

    2022. 8. 25.

    by. 카유.

    구현

     

    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
    뽑을 개수: 6

    getUniqueRandomNums(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] 이렇게 됩니다.

    댓글