@@ -1017,6 +1017,8 @@ which incur interpreter overhead.
10171017 "List unique elements, preserving order. Remember only the element just seen."
10181018 # unique_justseen('AAAABBBCCDAABBB') --> A B C D A B
10191019 # unique_justseen('ABBcCAD', str.lower) --> A B c A D
1020+ if key is None:
1021+ return map(operator.itemgetter(0), groupby(iterable))
10201022 return map(next, map(operator.itemgetter(1), groupby(iterable, key)))
10211023
10221024
@@ -1136,24 +1138,6 @@ The following recipes have a more mathematical flavor:
11361138 n = n // p * (p - 1)
11371139 return n
11381140
1139- def nth_combination(iterable, r, index):
1140- "Equivalent to list(combinations(iterable, r))[index]"
1141- pool = tuple(iterable)
1142- n = len(pool)
1143- c = math.comb(n, r)
1144- if index < 0:
1145- index += c
1146- if index < 0 or index >= c:
1147- raise IndexError
1148- result = []
1149- while r:
1150- c, n, r = c*r//n, n-1, r-1
1151- while index >= c:
1152- index -= c
1153- c, n = c*(n-r)//n, n-1
1154- result.append(pool[-1-n])
1155- return tuple(result)
1156-
11571141
11581142..doctest ::
11591143:hide:
@@ -1577,20 +1561,6 @@ The following recipes have a more mathematical flavor:
15771561 >>>first_true(' ABC0DEF1' ,' 9' ,str .isdigit)
15781562'0'
15791563
1580- >>>population= ' ABCDEFGH'
1581- >>>for rin range (len (population)+ 1 ):
1582- ...seq= list (combinations(population, r))
1583- ...for iin range (len (seq)):
1584- ...assert nth_combination(population, r, i)== seq[i]
1585- ...for iin range (- len (seq),0 ):
1586- ...assert nth_combination(population, r, i)== seq[i]
1587-
1588- >>>iterable= ' abcde'
1589- >>>r= 3
1590- >>>combos= list (combinations(iterable, r))
1591- >>>all (nth_combination(iterable, r, i)== combfor i, combin enumerate (combos))
1592- True
1593-
15941564
15951565..testcode ::
15961566:hide:
@@ -1617,6 +1587,24 @@ The following recipes have a more mathematical flavor:
16171587 for (a, _), (b, c) in pairwise(pairwise(iterable)):
16181588 yield a, b, c
16191589
1590+ def nth_combination(iterable, r, index):
1591+ "Equivalent to list(combinations(iterable, r))[index]"
1592+ pool = tuple(iterable)
1593+ n = len(pool)
1594+ c = math.comb(n, r)
1595+ if index < 0:
1596+ index += c
1597+ if index < 0 or index >= c:
1598+ raise IndexError
1599+ result = []
1600+ while r:
1601+ c, n, r = c*r//n, n-1, r-1
1602+ while index >= c:
1603+ index -= c
1604+ c, n = c*(n-r)//n, n-1
1605+ result.append(pool[-1-n])
1606+ return tuple(result)
1607+
16201608
16211609..doctest ::
16221610:hide:
@@ -1632,3 +1620,17 @@ The following recipes have a more mathematical flavor:
16321620
16331621 >>>list (triplewise(' ABCDEFG' ))
16341622[('A', 'B', 'C'), ('B', 'C', 'D'), ('C', 'D', 'E'), ('D', 'E', 'F'), ('E', 'F', 'G')]
1623+
1624+ >>>population= ' ABCDEFGH'
1625+ >>>for rin range (len (population)+ 1 ):
1626+ ...seq= list (combinations(population, r))
1627+ ...for iin range (len (seq)):
1628+ ...assert nth_combination(population, r, i)== seq[i]
1629+ ...for iin range (- len (seq),0 ):
1630+ ...assert nth_combination(population, r, i)== seq[i]
1631+
1632+ >>>iterable= ' abcde'
1633+ >>>r= 3
1634+ >>>combos= list (combinations(iterable, r))
1635+ >>>all (nth_combination(iterable, r, i)== combfor i, combin enumerate (combos))
1636+ True