Notice
Recent Posts
Recent Comments
Link
Nevertheless
[미니게임] Array.sort(Math.random())로 랜덤 추출하면 안 되는 이유🎰 본문
상식 퀴즈 부분에서 데이터 파일에 약 30개 정도의 문항을 객체 배열로 저장을 해두고, 이 배열에서 10개의 문항을 랜덤 추출을 해서 퀴즈를 구현하고자 했다.
export function getRandomQuestions(questions, count = 10) {
return [...questions]
.sort(() => Math.random() - 0.5)
.slice(0, count);
}
원래의 방식은 위와 같은 알고리즘으로 하고 있었다. gpt 의 추천으로 별 생각 없이 하고 있었는데, 뭔가 프로그램을 여러 번 돌려보면 자꾸 나왔던 문제들만 계속 나오는 듯한 느낌이 있었고, 이 부분을 개선해야겠다는 생각이 들었다.
🔬 문제 분석
array.sort((a, b) => Math.random() - 0.5)
이 함수는 Math.random() 으로 인해 같은 a,b 에 대해서도 호출될 때마다 다른 결과를 반환한다. 위의 코드대로 실행하면, 엔진은 두 요소를 비교할 때마다 그때그때 즉흥적으로 앞/뒤를 정해준다. 하지만 문제는, 정렬 알고리즘은 '전체 순서' 를 만들려고 한다는 점이다.
- sort 는 정렬 기준이 일관적이어야 한다.
- 하지만, Math.random() 은 매번 값이 달라진다.
- 즉, 정렬 기준이 계속 바뀌는 상태에서 정렬을 강요하게 된다. ➡️ 논리 붕괴
이로 인해,
- 어떤 요소는 앞쪽으로 갈 확률이 더 높아지고
- 어떤 요소는 뒤쪽으로 밀릴 가능성이 커진다.
- ➡️ 결과적으로 확률이 균등하지 않은 "가짜 랜덤"
🧪 해결 방법
export function getRandomQuestions(questions, count = 10) {
const shuffled = [...questions];
for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
return shuffled.slice(0, count);
}
- 배열의 뒤에서부터 하나씩 자리를 확정하면서, 아직 확정되지 않은 범위 내에서 랜덤 인덱스를 뽑아 swap 하는 방식
- 각 요소는 각 위치에 갈 확률이 동일하며, 정렬 기준이 흔들리지 않는다.
- 즉, 랜덤의 결과가 아니라 랜덤을 만드는 과정 자체가 균등하다.
'프로젝트' 카테고리의 다른 글
| [미니게임] 렌더링 중 navigate 호출로 발생한 React 경고 해결하기🛠️ (0) | 2026.02.09 |
|---|---|
| [미니게임] children 과 Outlet 는 뭐가 다를까❓ (0) | 2026.01.27 |
| [미니게임] onClick 에 함수를 바로 실행해서 생긴 버그🐞 (0) | 2026.01.22 |
| 🐝 디저비 프로젝트 회고 (0) | 2025.10.19 |
| 🏫 알바스쿨 프로젝트 회고 (0) | 2025.10.14 |