https://github.com/python/cpython/commit/5616ef92764c40f409d016897ce91acf2ab14f76
commit: 5616ef92764c40f409d016897ce91acf2ab14f76
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: rhettinger <[email protected]>
date: 2026-01-13T00:25:55Z
summary:

[3.13] gh-143762 Backport a6bc60d for random combinatoric recipes (GH-143764) 
(gh-143766)

files:
M Doc/library/random.rst

diff --git a/Doc/library/random.rst b/Doc/library/random.rst
index dd6b56106afe98..fdc14cd04e2230 100644
--- a/Doc/library/random.rst
+++ b/Doc/library/random.rst
@@ -633,11 +633,12 @@ These recipes show how to efficiently make random 
selections
 from the combinatoric iterators in the :mod:`itertools` module:
 
 .. testcode::
+
    import random
 
-   def random_product(*args, repeat=1):
-       "Random selection from itertools.product(*args, **kwds)"
-       pools = [tuple(pool) for pool in args] * repeat
+   def random_product(*iterables, repeat=1):
+       "Random selection from itertools.product(*iterables, repeat=repeat)"
+       pools = tuple(map(tuple, iterables)) * repeat
        return tuple(map(random.choice, pools))
 
    def random_permutation(iterable, r=None):
@@ -661,6 +662,91 @@ 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 stays in its original position."
+       seq = tuple(iterable)
+       if len(seq) < 2:
+           if not seq:
+               return ()
+           raise IndexError('No derangments to choose from')
+       perm = list(range(len(seq)))
+       start = tuple(perm)
+       while True:
+           random.shuffle(perm)
+           if all(p != q for p, q in zip(start, perm)):
+               return tuple([seq[i] for i in perm])
+
+.. doctest::
+    :hide:
+
+    >>> import random
+
+
+    >>> random.seed(8675309)
+    >>> random_product('ABCDEFG', repeat=5)
+    ('D', 'B', 'E', 'F', 'E')
+
+
+    >>> random.seed(8675309)
+    >>> random_permutation('ABCDEFG')
+    ('D', 'B', 'E', 'C', 'G', 'A', 'F')
+    >>> random_permutation('ABCDEFG', 5)
+    ('A', 'G', 'D', 'C', 'B')
+
+
+    >>> random.seed(8675309)
+    >>> random_combination('ABCDEFG', 7)
+    ('A', 'B', 'C', 'D', 'E', 'F', 'G')
+    >>> random_combination('ABCDEFG', 6)
+    ('A', 'B', 'C', 'D', 'F', 'G')
+    >>> random_combination('ABCDEFG', 5)
+    ('A', 'B', 'C', 'E', 'F')
+    >>> random_combination('ABCDEFG', 4)
+    ('B', 'C', 'D', 'G')
+    >>> random_combination('ABCDEFG', 3)
+    ('B', 'E', 'G')
+    >>> random_combination('ABCDEFG', 2)
+    ('E', 'G')
+    >>> random_combination('ABCDEFG', 1)
+    ('C',)
+    >>> random_combination('ABCDEFG', 0)
+    ()
+
+
+    >>> random.seed(8675309)
+    >>> random_combination_with_replacement('ABCDEFG', 7)
+    ('B', 'C', 'D', 'E', 'E', 'E', 'G')
+    >>> random_combination_with_replacement('ABCDEFG', 3)
+    ('A', 'B', 'E')
+    >>> random_combination_with_replacement('ABCDEFG', 2)
+    ('A', 'G')
+    >>> random_combination_with_replacement('ABCDEFG', 1)
+    ('E',)
+    >>> random_combination_with_replacement('ABCDEFG', 0)
+    ()
+
+
+    >>> random.seed(8675309)
+    >>> random_derangement('')
+    ()
+    >>> random_derangement('A')
+    Traceback (most recent call last):
+    ...
+    IndexError: No derangments to choose from
+    >>> random_derangement('AB')
+    ('B', 'A')
+    >>> random_derangement('ABC')
+    ('C', 'A', 'B')
+    >>> random_derangement('ABCD')
+    ('B', 'A', 'D', 'C')
+    >>> random_derangement('ABCDE')
+    ('B', 'C', 'A', 'E', 'D')
+    >>> # Identical inputs treated as distinct
+    >>> identical = 20
+    >>> random_derangement((10, identical, 30, identical))
+    (20, 30, 10, 20)
+
+
 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

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to