From f9a40c386d4d07dab1c15c6618807306a5119818 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Thu, 4 Sep 2025 10:50:29 -0500 Subject: [PATCH] Add random_derangement recipe gh-138377 --- Doc/library/random.rst | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Doc/library/random.rst b/Doc/library/random.rst index b1120b3a4d8e..e9cebf46d57b 100644 --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -630,7 +630,8 @@ Recipes ------- These recipes show how to efficiently make random selections -from the combinatoric iterators in the :mod:`itertools` module: +from the combinatoric iterators in the :mod:`itertools` module +or the :pypi:`more-itertools` project: .. testcode:: import random @@ -661,6 +662,17 @@ from the combinatoric iterators in the :mod:`itertools` module: indices = sorted(random.choices(range(n), k=r)) return tuple(pool[i] for i in indices) + def random_derangement(iterable): + "Choose a permutation where no element is in its original position." + seq = tuple(iterable) + if len(seq) < 2: + raise ValueError('derangments require at least two values') + perm = list(seq) + while True: + random.shuffle(perm) + if all(p != q for p, q in zip(seq, perm)): + return tuple(perm) + The default :func:`.random` returns multiples of 2⁻⁵³ in the range *0.0 ≤ x < 1.0*. All such numbers are evenly spaced and are exactly representable as Python floats. However, many other representable -- 2.47.3