shuffle
원소 순서를 뒤섞은 새 리스트를 반환합니다 — 시드를 넘기면 결과를 재현할 수 있습니다.
강의
shuffle은 iterable의 원소에 Fisher-Yates 셔플을
적용해 완전히 새로운 List<T>를 반환합니다 —
입력은 절대 변경되지 않습니다. 시드 없이 호출하면
dart:math의 Random을 사용하므로 호출할 때마다
순서가 달라집니다. 카드 덱을 섞거나 퀴즈 문항을 무작위로 배치할 때
기대하는 그대로입니다.
int 타입의 seed를 넘기면 시드 기반 PRNG로
전환됩니다(FxTS가 쓰는 것과 같은 Mulberry32 계열 생성기를 Dart로
포팅했습니다). 그래서 같은 시드는 언제나 같은 순서를 만들어냅니다 —
어떤 실행에서든, 어떤 머신에서든 마찬가지입니다. 이 결정성 덕분에
시드 셔플은 재현 가능한 테스트 픽스처, 오늘의 시드를 가진 모두가 같은
배치를 보게 되는 "일일 챌린지" 퍼즐, 무작위 시뮬레이션의 결정적 리플레이
같은 곳에 유용합니다.
shuffleAsync는 *Async 짝입니다. 내부적으로
toListAsync를 통해 FxAsyncIterable을 먼저
구체화한 다음 그 결과를 섞기 때문에, 같은 시드를 주면 시드 기반 비동기
셔플은 동기 버전과 완전히 동일한 순서를 만들어냅니다.
데모 1 · 시드로 얻는 결정성
같은 시드라면 언제나 같은 순서입니다. 시드가 다르면 순서도 달라지지만, 그 순서 역시 재현 가능합니다:
데모 2 · shuffleAsync는 동기와 같은 순서를 내고, 원소는 하나도 잃지 않습니다
소스가 동기든 비동기든 같은 시드면 순서가 동일합니다 — 그리고 입력의 모든 원소는 순서만 바뀐 채 그대로 남아 있습니다:
메서드 표기
xs.fxShuffle(seed)는 shuffle(xs, seed)이고,
FxAsyncIterable에서 같은 이름은
shuffleAsync입니다.
이름이 shuffle이 아닌 것은 취향 문제가 아닙니다.
List.shuffle은 이미 dart:core에 있고,
제자리에서 섞고 void를 돌려줍니다. 인스턴스 멤버는 항상
확장을 이기므로 List를 수신자로 두면 조용히 엉뚱한 쪽이
불립니다 — 접두사가 둘을 헷갈릴 수 없게 만듭니다.
final a = [1, 2, 3].fxShuffle(42); // a new List, seeded
final b = [1, 2, 3]..shuffle(); // dart:core, in place, void
직접 해 보기
연습: 이 턴 순서에 시드를 주어, 매번 무작위로 바뀌는 대신 앱을 재시작해도 재현되도록 만들어 보세요.