8579620785fc3c5a0ed7a47a4f97dc52dced7e02
[SubU] /
1 """Imported from the recipes section of the itertools documentation.
2
3 All functions taken from the recipes section of the itertools library docs
4 [1]_.
5 Some backward-compatible usability improvements have been made.
6
7 .. [1] http://docs.python.org/library/itertools.html#recipes
8
9 """
10 import math
11 import operator
12
13 from collections import deque
14 from collections.abc import Sized
15 from functools import reduce
16 from itertools import (
17     chain,
18     combinations,
19     compress,
20     count,
21     cycle,
22     groupby,
23     islice,
24     repeat,
25     starmap,
26     tee,
27     zip_longest,
28 )
29 from random import randrange, sample, choice
30
31 __all__ = [
32     'all_equal',
33     'batched',
34     'before_and_after',
35     'consume',
36     'convolve',
37     'dotproduct',
38     'first_true',
39     'flatten',
40     'grouper',
41     'iter_except',
42     'ncycles',
43     'nth',
44     'nth_combination',
45     'padnone',
46     'pad_none',
47     'pairwise',
48     'partition',
49     'polynomial_from_roots',
50     'powerset',
51     'prepend',
52     'quantify',
53     'random_combination_with_replacement',
54     'random_combination',
55     'random_permutation',
56     'random_product',
57     'repeatfunc',
58     'roundrobin',
59     'sieve',
60     'sliding_window',
61     'subslices',
62     'tabulate',
63     'tail',
64     'take',
65     'triplewise',
66     'unique_everseen',
67     'unique_justseen',
68 ]
69
70 _marker = object()
71
72
73 def take(n, iterable):
74     """Return first *n* items of the iterable as a list.
75
76         >>> take(3, range(10))
77         [0, 1, 2]
78
79     If there are fewer than *n* items in the iterable, all of them are
80     returned.
81
82         >>> take(10, range(3))
83         [0, 1, 2]
84
85     """
86     return list(islice(iterable, n))
87
88
89 def tabulate(function, start=0):
90     """Return an iterator over the results of ``func(start)``,
91     ``func(start + 1)``, ``func(start + 2)``...
92
93     *func* should be a function that accepts one integer argument.
94
95     If *start* is not specified it defaults to 0. It will be incremented each
96     time the iterator is advanced.
97
98         >>> square = lambda x: x ** 2
99         >>> iterator = tabulate(square, -3)
100         >>> take(4, iterator)
101         [9, 4, 1, 0]
102
103     """
104     return map(function, count(start))
105
106
107 def tail(n, iterable):
108     """Return an iterator over the last *n* items of *iterable*.
109
110     >>> t = tail(3, 'ABCDEFG')
111     >>> list(t)
112     ['E', 'F', 'G']
113
114     """
115     # If the given iterable has a length, then we can use islice to get its
116     # final elements. Note that if the iterable is not actually Iterable,
117     # either islice or deque will throw a TypeError. This is why we don't
118     # check if it is Iterable.
119     if isinstance(iterable, Sized):
120         yield from islice(iterable, max(0, len(iterable) - n), None)
121     else:
122         yield from iter(deque(iterable, maxlen=n))
123
124
125 def consume(iterator, n=None):
126     """Advance *iterable* by *n* steps. If *n* is ``None``, consume it
127     entirely.
128
129     Efficiently exhausts an iterator without returning values. Defaults to
130     consuming the whole iterator, but an optional second argument may be
131     provided to limit consumption.
132
133         >>> i = (x for x in range(10))
134         >>> next(i)
135         0
136         >>> consume(i, 3)
137         >>> next(i)
138         4
139         >>> consume(i)
140         >>> next(i)
141         Traceback (most recent call last):
142           File "<stdin>", line 1, in <module>
143         StopIteration
144
145     If the iterator has fewer items remaining than the provided limit, the
146     whole iterator will be consumed.
147
148         >>> i = (x for x in range(3))
149         >>> consume(i, 5)
150         >>> next(i)
151         Traceback (most recent call last):
152           File "<stdin>", line 1, in <module>
153         StopIteration
154
155     """
156     # Use functions that consume iterators at C speed.
157     if n is None:
158         # feed the entire iterator into a zero-length deque
159         deque(iterator, maxlen=0)
160     else:
161         # advance to the empty slice starting at position n
162         next(islice(iterator, n, n), None)
163
164
165 def nth(iterable, n, default=None):
166     """Returns the nth item or a default value.
167
168     >>> l = range(10)
169     >>> nth(l, 3)
170     3
171     >>> nth(l, 20, "zebra")
172     'zebra'
173
174     """
175     return next(islice(iterable, n, None), default)
176
177
178 def all_equal(iterable):
179     """
180     Returns ``True`` if all the elements are equal to each other.
181
182         >>> all_equal('aaaa')
183         True
184         >>> all_equal('aaab')
185         False
186
187     """
188     g = groupby(iterable)
189     return next(g, True) and not next(g, False)
190
191
192 def quantify(iterable, pred=bool):
193     """Return the how many times the predicate is true.
194
195     >>> quantify([True, False, True])
196     2
197
198     """
199     return sum(map(pred, iterable))
200
201
202 def pad_none(iterable):
203     """Returns the sequence of elements and then returns ``None`` indefinitely.
204
205         >>> take(5, pad_none(range(3)))
206         [0, 1, 2, None, None]
207
208     Useful for emulating the behavior of the built-in :func:`map` function.
209
210     See also :func:`padded`.
211
212     """
213     return chain(iterable, repeat(None))
214
215
216 padnone = pad_none
217
218
219 def ncycles(iterable, n):
220     """Returns the sequence elements *n* times
221
222     >>> list(ncycles(["a", "b"], 3))
223     ['a', 'b', 'a', 'b', 'a', 'b']
224
225     """
226     return chain.from_iterable(repeat(tuple(iterable), n))
227
228
229 def dotproduct(vec1, vec2):
230     """Returns the dot product of the two iterables.
231
232     >>> dotproduct([10, 10], [20, 20])
233     400
234
235     """
236     return sum(map(operator.mul, vec1, vec2))
237
238
239 def flatten(listOfLists):
240     """Return an iterator flattening one level of nesting in a list of lists.
241
242         >>> list(flatten([[0, 1], [2, 3]]))
243         [0, 1, 2, 3]
244
245     See also :func:`collapse`, which can flatten multiple levels of nesting.
246
247     """
248     return chain.from_iterable(listOfLists)
249
250
251 def repeatfunc(func, times=None, *args):
252     """Call *func* with *args* repeatedly, returning an iterable over the
253     results.
254
255     If *times* is specified, the iterable will terminate after that many
256     repetitions:
257
258         >>> from operator import add
259         >>> times = 4
260         >>> args = 3, 5
261         >>> list(repeatfunc(add, times, *args))
262         [8, 8, 8, 8]
263
264     If *times* is ``None`` the iterable will not terminate:
265
266         >>> from random import randrange
267         >>> times = None
268         >>> args = 1, 11
269         >>> take(6, repeatfunc(randrange, times, *args))  # doctest:+SKIP
270         [2, 4, 8, 1, 8, 4]
271
272     """
273     if times is None:
274         return starmap(func, repeat(args))
275     return starmap(func, repeat(args, times))
276
277
278 def _pairwise(iterable):
279     """Returns an iterator of paired items, overlapping, from the original
280
281     >>> take(4, pairwise(count()))
282     [(0, 1), (1, 2), (2, 3), (3, 4)]
283
284     On Python 3.10 and above, this is an alias for :func:`itertools.pairwise`.
285
286     """
287     a, b = tee(iterable)
288     next(b, None)
289     yield from zip(a, b)
290
291
292 try:
293     from itertools import pairwise as itertools_pairwise
294 except ImportError:
295     pairwise = _pairwise
296 else:
297
298     def pairwise(iterable):
299         yield from itertools_pairwise(iterable)
300
301     pairwise.__doc__ = _pairwise.__doc__
302
303
304 class UnequalIterablesError(ValueError):
305     def __init__(self, details=None):
306         msg = 'Iterables have different lengths'
307         if details is not None:
308             msg += (': index 0 has length {}; index {} has length {}').format(
309                 *details
310             )
311
312         super().__init__(msg)
313
314
315 def _zip_equal_generator(iterables):
316     for combo in zip_longest(*iterables, fillvalue=_marker):
317         for val in combo:
318             if val is _marker:
319                 raise UnequalIterablesError()
320         yield combo
321
322
323 def _zip_equal(*iterables):
324     # Check whether the iterables are all the same size.
325     try:
326         first_size = len(iterables[0])
327         for i, it in enumerate(iterables[1:], 1):
328             size = len(it)
329             if size != first_size:
330                 break
331         else:
332             # If we didn't break out, we can use the built-in zip.
333             return zip(*iterables)
334
335         # If we did break out, there was a mismatch.
336         raise UnequalIterablesError(details=(first_size, i, size))
337     # If any one of the iterables didn't have a length, start reading
338     # them until one runs out.
339     except TypeError:
340         return _zip_equal_generator(iterables)
341
342
343 def grouper(iterable, n, incomplete='fill', fillvalue=None):
344     """Group elements from *iterable* into fixed-length groups of length *n*.
345
346     >>> list(grouper('ABCDEF', 3))
347     [('A', 'B', 'C'), ('D', 'E', 'F')]
348
349     The keyword arguments *incomplete* and *fillvalue* control what happens for
350     iterables whose length is not a multiple of *n*.
351
352     When *incomplete* is `'fill'`, the last group will contain instances of
353     *fillvalue*.
354
355     >>> list(grouper('ABCDEFG', 3, incomplete='fill', fillvalue='x'))
356     [('A', 'B', 'C'), ('D', 'E', 'F'), ('G', 'x', 'x')]
357
358     When *incomplete* is `'ignore'`, the last group will not be emitted.
359
360     >>> list(grouper('ABCDEFG', 3, incomplete='ignore', fillvalue='x'))
361     [('A', 'B', 'C'), ('D', 'E', 'F')]
362
363     When *incomplete* is `'strict'`, a subclass of `ValueError` will be raised.
364
365     >>> it = grouper('ABCDEFG', 3, incomplete='strict')
366     >>> list(it)  # doctest: +IGNORE_EXCEPTION_DETAIL
367     Traceback (most recent call last):
368     ...
369     UnequalIterablesError
370
371     """
372     args = [iter(iterable)] * n
373     if incomplete == 'fill':
374         return zip_longest(*args, fillvalue=fillvalue)
375     if incomplete == 'strict':
376         return _zip_equal(*args)
377     if incomplete == 'ignore':
378         return zip(*args)
379     else:
380         raise ValueError('Expected fill, strict, or ignore')
381
382
383 def roundrobin(*iterables):
384     """Yields an item from each iterable, alternating between them.
385
386         >>> list(roundrobin('ABC', 'D', 'EF'))
387         ['A', 'D', 'E', 'B', 'F', 'C']
388
389     This function produces the same output as :func:`interleave_longest`, but
390     may perform better for some inputs (in particular when the number of
391     iterables is small).
392
393     """
394     # Recipe credited to George Sakkis
395     pending = len(iterables)
396     nexts = cycle(iter(it).__next__ for it in iterables)
397     while pending:
398         try:
399             for next in nexts:
400                 yield next()
401         except StopIteration:
402             pending -= 1
403             nexts = cycle(islice(nexts, pending))
404
405
406 def partition(pred, iterable):
407     """
408     Returns a 2-tuple of iterables derived from the input iterable.
409     The first yields the items that have ``pred(item) == False``.
410     The second yields the items that have ``pred(item) == True``.
411
412         >>> is_odd = lambda x: x % 2 != 0
413         >>> iterable = range(10)
414         >>> even_items, odd_items = partition(is_odd, iterable)
415         >>> list(even_items), list(odd_items)
416         ([0, 2, 4, 6, 8], [1, 3, 5, 7, 9])
417
418     If *pred* is None, :func:`bool` is used.
419
420         >>> iterable = [0, 1, False, True, '', ' ']
421         >>> false_items, true_items = partition(None, iterable)
422         >>> list(false_items), list(true_items)
423         ([0, False, ''], [1, True, ' '])
424
425     """
426     if pred is None:
427         pred = bool
428
429     evaluations = ((pred(x), x) for x in iterable)
430     t1, t2 = tee(evaluations)
431     return (
432         (x for (cond, x) in t1 if not cond),
433         (x for (cond, x) in t2 if cond),
434     )
435
436
437 def powerset(iterable):
438     """Yields all possible subsets of the iterable.
439
440         >>> list(powerset([1, 2, 3]))
441         [(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
442
443     :func:`powerset` will operate on iterables that aren't :class:`set`
444     instances, so repeated elements in the input will produce repeated elements
445     in the output. Use :func:`unique_everseen` on the input to avoid generating
446     duplicates:
447
448         >>> seq = [1, 1, 0]
449         >>> list(powerset(seq))
450         [(), (1,), (1,), (0,), (1, 1), (1, 0), (1, 0), (1, 1, 0)]
451         >>> from more_itertools import unique_everseen
452         >>> list(powerset(unique_everseen(seq)))
453         [(), (1,), (0,), (1, 0)]
454
455     """
456     s = list(iterable)
457     return chain.from_iterable(combinations(s, r) for r in range(len(s) + 1))
458
459
460 def unique_everseen(iterable, key=None):
461     """
462     Yield unique elements, preserving order.
463
464         >>> list(unique_everseen('AAAABBBCCDAABBB'))
465         ['A', 'B', 'C', 'D']
466         >>> list(unique_everseen('ABBCcAD', str.lower))
467         ['A', 'B', 'C', 'D']
468
469     Sequences with a mix of hashable and unhashable items can be used.
470     The function will be slower (i.e., `O(n^2)`) for unhashable items.
471
472     Remember that ``list`` objects are unhashable - you can use the *key*
473     parameter to transform the list to a tuple (which is hashable) to
474     avoid a slowdown.
475
476         >>> iterable = ([1, 2], [2, 3], [1, 2])
477         >>> list(unique_everseen(iterable))  # Slow
478         [[1, 2], [2, 3]]
479         >>> list(unique_everseen(iterable, key=tuple))  # Faster
480         [[1, 2], [2, 3]]
481
482     Similary, you may want to convert unhashable ``set`` objects with
483     ``key=frozenset``. For ``dict`` objects,
484     ``key=lambda x: frozenset(x.items())`` can be used.
485
486     """
487     seenset = set()
488     seenset_add = seenset.add
489     seenlist = []
490     seenlist_add = seenlist.append
491     use_key = key is not None
492
493     for element in iterable:
494         k = key(element) if use_key else element
495         try:
496             if k not in seenset:
497                 seenset_add(k)
498                 yield element
499         except TypeError:
500             if k not in seenlist:
501                 seenlist_add(k)
502                 yield element
503
504
505 def unique_justseen(iterable, key=None):
506     """Yields elements in order, ignoring serial duplicates
507
508     >>> list(unique_justseen('AAAABBBCCDAABBB'))
509     ['A', 'B', 'C', 'D', 'A', 'B']
510     >>> list(unique_justseen('ABBCcAD', str.lower))
511     ['A', 'B', 'C', 'A', 'D']
512
513     """
514     return map(next, map(operator.itemgetter(1), groupby(iterable, key)))
515
516
517 def iter_except(func, exception, first=None):
518     """Yields results from a function repeatedly until an exception is raised.
519
520     Converts a call-until-exception interface to an iterator interface.
521     Like ``iter(func, sentinel)``, but uses an exception instead of a sentinel
522     to end the loop.
523
524         >>> l = [0, 1, 2]
525         >>> list(iter_except(l.pop, IndexError))
526         [2, 1, 0]
527
528     Multiple exceptions can be specified as a stopping condition:
529
530         >>> l = [1, 2, 3, '...', 4, 5, 6]
531         >>> list(iter_except(lambda: 1 + l.pop(), (IndexError, TypeError)))
532         [7, 6, 5]
533         >>> list(iter_except(lambda: 1 + l.pop(), (IndexError, TypeError)))
534         [4, 3, 2]
535         >>> list(iter_except(lambda: 1 + l.pop(), (IndexError, TypeError)))
536         []
537
538     """
539     try:
540         if first is not None:
541             yield first()
542         while 1:
543             yield func()
544     except exception:
545         pass
546
547
548 def first_true(iterable, default=None, pred=None):
549     """
550     Returns the first true value in the iterable.
551
552     If no true value is found, returns *default*
553
554     If *pred* is not None, returns the first item for which
555     ``pred(item) == True`` .
556
557         >>> first_true(range(10))
558         1
559         >>> first_true(range(10), pred=lambda x: x > 5)
560         6
561         >>> first_true(range(10), default='missing', pred=lambda x: x > 9)
562         'missing'
563
564     """
565     return next(filter(pred, iterable), default)
566
567
568 def random_product(*args, repeat=1):
569     """Draw an item at random from each of the input iterables.
570
571         >>> random_product('abc', range(4), 'XYZ')  # doctest:+SKIP
572         ('c', 3, 'Z')
573
574     If *repeat* is provided as a keyword argument, that many items will be
575     drawn from each iterable.
576
577         >>> random_product('abcd', range(4), repeat=2)  # doctest:+SKIP
578         ('a', 2, 'd', 3)
579
580     This equivalent to taking a random selection from
581     ``itertools.product(*args, **kwarg)``.
582
583     """
584     pools = [tuple(pool) for pool in args] * repeat
585     return tuple(choice(pool) for pool in pools)
586
587
588 def random_permutation(iterable, r=None):
589     """Return a random *r* length permutation of the elements in *iterable*.
590
591     If *r* is not specified or is ``None``, then *r* defaults to the length of
592     *iterable*.
593
594         >>> random_permutation(range(5))  # doctest:+SKIP
595         (3, 4, 0, 1, 2)
596
597     This equivalent to taking a random selection from
598     ``itertools.permutations(iterable, r)``.
599
600     """
601     pool = tuple(iterable)
602     r = len(pool) if r is None else r
603     return tuple(sample(pool, r))
604
605
606 def random_combination(iterable, r):
607     """Return a random *r* length subsequence of the elements in *iterable*.
608
609         >>> random_combination(range(5), 3)  # doctest:+SKIP
610         (2, 3, 4)
611
612     This equivalent to taking a random selection from
613     ``itertools.combinations(iterable, r)``.
614
615     """
616     pool = tuple(iterable)
617     n = len(pool)
618     indices = sorted(sample(range(n), r))
619     return tuple(pool[i] for i in indices)
620
621
622 def random_combination_with_replacement(iterable, r):
623     """Return a random *r* length subsequence of elements in *iterable*,
624     allowing individual elements to be repeated.
625
626         >>> random_combination_with_replacement(range(3), 5) # doctest:+SKIP
627         (0, 0, 1, 2, 2)
628
629     This equivalent to taking a random selection from
630     ``itertools.combinations_with_replacement(iterable, r)``.
631
632     """
633     pool = tuple(iterable)
634     n = len(pool)
635     indices = sorted(randrange(n) for i in range(r))
636     return tuple(pool[i] for i in indices)
637
638
639 def nth_combination(iterable, r, index):
640     """Equivalent to ``list(combinations(iterable, r))[index]``.
641
642     The subsequences of *iterable* that are of length *r* can be ordered
643     lexicographically. :func:`nth_combination` computes the subsequence at
644     sort position *index* directly, without computing the previous
645     subsequences.
646
647         >>> nth_combination(range(5), 3, 5)
648         (0, 3, 4)
649
650     ``ValueError`` will be raised If *r* is negative or greater than the length
651     of *iterable*.
652     ``IndexError`` will be raised if the given *index* is invalid.
653     """
654     pool = tuple(iterable)
655     n = len(pool)
656     if (r < 0) or (r > n):
657         raise ValueError
658
659     c = 1
660     k = min(r, n - r)
661     for i in range(1, k + 1):
662         c = c * (n - k + i) // i
663
664     if index < 0:
665         index += c
666
667     if (index < 0) or (index >= c):
668         raise IndexError
669
670     result = []
671     while r:
672         c, n, r = c * r // n, n - 1, r - 1
673         while index >= c:
674             index -= c
675             c, n = c * (n - r) // n, n - 1
676         result.append(pool[-1 - n])
677
678     return tuple(result)
679
680
681 def prepend(value, iterator):
682     """Yield *value*, followed by the elements in *iterator*.
683
684         >>> value = '0'
685         >>> iterator = ['1', '2', '3']
686         >>> list(prepend(value, iterator))
687         ['0', '1', '2', '3']
688
689     To prepend multiple values, see :func:`itertools.chain`
690     or :func:`value_chain`.
691
692     """
693     return chain([value], iterator)
694
695
696 def convolve(signal, kernel):
697     """Convolve the iterable *signal* with the iterable *kernel*.
698
699         >>> signal = (1, 2, 3, 4, 5)
700         >>> kernel = [3, 2, 1]
701         >>> list(convolve(signal, kernel))
702         [3, 8, 14, 20, 26, 14, 5]
703
704     Note: the input arguments are not interchangeable, as the *kernel*
705     is immediately consumed and stored.
706
707     """
708     kernel = tuple(kernel)[::-1]
709     n = len(kernel)
710     window = deque([0], maxlen=n) * n
711     for x in chain(signal, repeat(0, n - 1)):
712         window.append(x)
713         yield sum(map(operator.mul, kernel, window))
714
715
716 def before_and_after(predicate, it):
717     """A variant of :func:`takewhile` that allows complete access to the
718     remainder of the iterator.
719
720          >>> it = iter('ABCdEfGhI')
721          >>> all_upper, remainder = before_and_after(str.isupper, it)
722          >>> ''.join(all_upper)
723          'ABC'
724          >>> ''.join(remainder) # takewhile() would lose the 'd'
725          'dEfGhI'
726
727     Note that the first iterator must be fully consumed before the second
728     iterator can generate valid results.
729     """
730     it = iter(it)
731     transition = []
732
733     def true_iterator():
734         for elem in it:
735             if predicate(elem):
736                 yield elem
737             else:
738                 transition.append(elem)
739                 return
740
741     # Note: this is different from itertools recipes to allow nesting
742     # before_and_after remainders into before_and_after again. See tests
743     # for an example.
744     remainder_iterator = chain(transition, it)
745
746     return true_iterator(), remainder_iterator
747
748
749 def triplewise(iterable):
750     """Return overlapping triplets from *iterable*.
751
752     >>> list(triplewise('ABCDE'))
753     [('A', 'B', 'C'), ('B', 'C', 'D'), ('C', 'D', 'E')]
754
755     """
756     for (a, _), (b, c) in pairwise(pairwise(iterable)):
757         yield a, b, c
758
759
760 def sliding_window(iterable, n):
761     """Return a sliding window of width *n* over *iterable*.
762
763         >>> list(sliding_window(range(6), 4))
764         [(0, 1, 2, 3), (1, 2, 3, 4), (2, 3, 4, 5)]
765
766     If *iterable* has fewer than *n* items, then nothing is yielded:
767
768         >>> list(sliding_window(range(3), 4))
769         []
770
771     For a variant with more features, see :func:`windowed`.
772     """
773     it = iter(iterable)
774     window = deque(islice(it, n), maxlen=n)
775     if len(window) == n:
776         yield tuple(window)
777     for x in it:
778         window.append(x)
779         yield tuple(window)
780
781
782 def subslices(iterable):
783     """Return all contiguous non-empty subslices of *iterable*.
784
785         >>> list(subslices('ABC'))
786         [['A'], ['A', 'B'], ['A', 'B', 'C'], ['B'], ['B', 'C'], ['C']]
787
788     This is similar to :func:`substrings`, but emits items in a different
789     order.
790     """
791     seq = list(iterable)
792     slices = starmap(slice, combinations(range(len(seq) + 1), 2))
793     return map(operator.getitem, repeat(seq), slices)
794
795
796 def polynomial_from_roots(roots):
797     """Compute a polynomial's coefficients from its roots.
798
799     >>> roots = [5, -4, 3]  # (x - 5) * (x + 4) * (x - 3)
800     >>> polynomial_from_roots(roots)  # x^3 - 4 * x^2 - 17 * x + 60
801     [1, -4, -17, 60]
802     """
803     # Use math.prod for Python 3.8+,
804     prod = getattr(math, 'prod', lambda x: reduce(operator.mul, x, 1))
805     roots = list(map(operator.neg, roots))
806     return [
807         sum(map(prod, combinations(roots, k))) for k in range(len(roots) + 1)
808     ]
809
810
811 def sieve(n):
812     """Yield the primes less than n.
813
814     >>> list(sieve(30))
815     [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
816     """
817     isqrt = getattr(math, 'isqrt', lambda x: int(math.sqrt(x)))
818     limit = isqrt(n) + 1
819     data = bytearray([1]) * n
820     data[:2] = 0, 0
821     for p in compress(range(limit), data):
822         data[p + p : n : p] = bytearray(len(range(p + p, n, p)))
823
824     return compress(count(), data)
825
826
827 def batched(iterable, n):
828     """Batch data into lists of length *n*. The last batch may be shorter.
829
830     >>> list(batched('ABCDEFG', 3))
831     [['A', 'B', 'C'], ['D', 'E', 'F'], ['G']]
832
833     This recipe is from the ``itertools`` docs. This library also provides
834     :func:`chunked`, which has a different implementation.
835     """
836     it = iter(iterable)
837     while True:
838         batch = list(islice(it, n))
839         if not batch:
840             break
841         yield batch