itertools.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896
  1. # -*- coding: UTF-8 -*-
  2. """
  3. jaraco.itertools
  4. Tools for working with iterables. Complements itertools and more_itertools.
  5. """
  6. from __future__ import absolute_import, unicode_literals, print_function
  7. import operator
  8. import itertools
  9. import collections
  10. import math
  11. import warnings
  12. import six
  13. from six.moves import queue, xrange as range
  14. import inflect
  15. from more_itertools import more
  16. from more_itertools import recipes
  17. def make_rows(num_columns, seq):
  18. """
  19. Make a sequence into rows of num_columns columns.
  20. >>> tuple(make_rows(2, [1, 2, 3, 4, 5]))
  21. ((1, 4), (2, 5), (3, None))
  22. >>> tuple(make_rows(3, [1, 2, 3, 4, 5]))
  23. ((1, 3, 5), (2, 4, None))
  24. """
  25. # calculate the minimum number of rows necessary to fit the list in
  26. # num_columns Columns
  27. num_rows, partial = divmod(len(seq), num_columns)
  28. if partial:
  29. num_rows += 1
  30. # break the seq into num_columns of length num_rows
  31. result = recipes.grouper(num_rows, seq)
  32. # result is now a list of columns... transpose it to return a list
  33. # of rows
  34. return zip(*result)
  35. def bisect(seq, func=bool):
  36. """
  37. Split a sequence into two sequences: the first is elements that
  38. return False for func(element) and the second for True for
  39. func(element).
  40. By default, func is ``bool``, so uses the truth value of the object.
  41. >>> is_odd = lambda n: n%2
  42. >>> even, odd = bisect(range(5), is_odd)
  43. >>> list(odd)
  44. [1, 3]
  45. >>> list(even)
  46. [0, 2, 4]
  47. >>> zeros, other = bisect(reversed(range(5)))
  48. >>> list(zeros)
  49. [0]
  50. >>> list(other)
  51. [4, 3, 2, 1]
  52. """
  53. queues = GroupbySaved(seq, func)
  54. return queues.get_first_n_queues(2)
  55. class GroupbySaved(object):
  56. """
  57. Split a sequence into n sequences where n is determined by the
  58. number of distinct values returned by a key function applied to each
  59. element in the sequence.
  60. >>> truthsplit = GroupbySaved(['Test', '', 30, None], bool)
  61. >>> truthsplit['x']
  62. Traceback (most recent call last):
  63. ...
  64. KeyError: 'x'
  65. >>> true_items = truthsplit[True]
  66. >>> false_items = truthsplit[False]
  67. >>> tuple(iter(false_items))
  68. ('', None)
  69. >>> tuple(iter(true_items))
  70. ('Test', 30)
  71. >>> every_third_split = GroupbySaved(range(99), lambda n: n%3)
  72. >>> zeros = every_third_split[0]
  73. >>> ones = every_third_split[1]
  74. >>> twos = every_third_split[2]
  75. >>> next(zeros)
  76. 0
  77. >>> next(zeros)
  78. 3
  79. >>> next(ones)
  80. 1
  81. >>> next(twos)
  82. 2
  83. >>> next(ones)
  84. 4
  85. """
  86. def __init__(self, sequence, func = lambda x: x):
  87. self.sequence = iter(sequence)
  88. self.func = func
  89. self.queues = dict()
  90. def __getitem__(self, key):
  91. try:
  92. return self.queues[key]
  93. except KeyError:
  94. return self.__find_queue__(key)
  95. def __fetch__(self):
  96. "get the next item from the sequence and queue it up"
  97. item = next(self.sequence)
  98. key = self.func(item)
  99. queue = self.queues.setdefault(key, FetchingQueue(self.__fetch__))
  100. queue.enqueue(item)
  101. def __find_queue__(self, key):
  102. "search for the queue indexed by key"
  103. try:
  104. while not key in self.queues:
  105. self.__fetch__()
  106. return self.queues[key]
  107. except StopIteration:
  108. raise KeyError(key)
  109. def get_first_n_queues(self, n):
  110. """
  111. Run through the sequence until n queues are created and return
  112. them. If fewer are created, return those plus empty iterables to
  113. compensate.
  114. """
  115. try:
  116. while len(self.queues) < n:
  117. self.__fetch__()
  118. except StopIteration:
  119. pass
  120. values = list(self.queues.values())
  121. missing = n - len(values)
  122. values.extend(iter([]) for n in range(missing))
  123. return values
  124. class FetchingQueue(queue.Queue):
  125. """
  126. A FIFO Queue that is supplied with a function to inject more into
  127. the queue if it is empty.
  128. >>> values = iter(range(10))
  129. >>> get_value = lambda: globals()['q'].enqueue(next(values))
  130. >>> q = FetchingQueue(get_value)
  131. >>> [x for x in q] == list(range(10))
  132. True
  133. Note that tuple(q) or list(q) would not have worked above because
  134. tuple(q) just copies the elements in the list (of which there are
  135. none).
  136. """
  137. def __init__(self, fetcher):
  138. if six.PY3:
  139. super(FetchingQueue, self).__init__()
  140. else:
  141. queue.Queue.__init__(self)
  142. self._fetcher = fetcher
  143. def __next__(self):
  144. while self.empty():
  145. self._fetcher()
  146. return self.get()
  147. next = __next__
  148. def __iter__(self):
  149. while True:
  150. yield next(self)
  151. def enqueue(self, item):
  152. self.put_nowait(item)
  153. class Count(object):
  154. """
  155. A stop object that will count how many times it's been called and return
  156. False on the N+1st call. Useful for use with takewhile.
  157. >>> tuple(itertools.takewhile(Count(5), range(20)))
  158. (0, 1, 2, 3, 4)
  159. >>> print('catch', Count(5))
  160. catch at most 5
  161. It's possible to construct a Count with no limit or infinite limit.
  162. >>> unl_c = Count(None)
  163. >>> inf_c = Count(float('Inf'))
  164. Unlimited or limited by infinity are equivalent.
  165. >>> unl_c == inf_c
  166. True
  167. An unlimited counter is useful for wrapping an iterable to get the
  168. count after it's consumed.
  169. >>> tuple(itertools.takewhile(unl_c, range(20)))[-3:]
  170. (17, 18, 19)
  171. >>> unl_c.count
  172. 20
  173. If all you need is the count of items, consider :class:`Counter` instead.
  174. """
  175. def __init__(self, limit):
  176. self.count = 0
  177. self.limit = limit if limit is not None else float('Inf')
  178. def __call__(self, arg):
  179. if self.count > self.limit:
  180. raise ValueError("Should not call count stop more anymore.")
  181. self.count += 1
  182. return self.count <= self.limit
  183. def __str__(self):
  184. if self.limit:
  185. return 'at most %d' % self.limit
  186. else:
  187. return 'all'
  188. def __eq__(self, other):
  189. return vars(self) == vars(other)
  190. class islice(object):
  191. """May be applied to an iterable to limit the number of items returned.
  192. Works similarly to count, except is called only once on an iterable.
  193. Functionality is identical to islice, except for __str__ and reusability.
  194. >>> tuple(islice(5).apply(range(20)))
  195. (0, 1, 2, 3, 4)
  196. >>> tuple(islice(None).apply(range(20)))
  197. (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19)
  198. >>> print(islice(3, 10))
  199. items 3 to 9
  200. >>> print(islice(3, 10, 2))
  201. every 2nd item from 3 to 9
  202. """
  203. def __init__(self, *sliceArgs):
  204. self.sliceArgs = sliceArgs
  205. def apply(self, i):
  206. return itertools.islice(i, *self.sliceArgs)
  207. def __str__(self):
  208. if self.sliceArgs == (None,):
  209. result = 'all'
  210. else:
  211. result = self._formatArgs()
  212. return result
  213. def _formatArgs(self):
  214. slice_range = lambda a_b: '%d to %d' % (a_b[0], a_b[1] - 1)
  215. if len(self.sliceArgs) == 1:
  216. result = 'at most %d' % self.sliceArgs
  217. if len(self.sliceArgs) == 2:
  218. result = 'items %s' % slice_range(self.sliceArgs)
  219. if len(self.sliceArgs) == 3:
  220. ord = inflect.engine().ordinal(self.sliceArgs[2])
  221. range = slice_range(self.sliceArgs[0:2])
  222. result = 'every %(ord)s item from %(range)s' % locals()
  223. return result
  224. class LessThanNBlanks(object):
  225. """
  226. An object that when called will return True until n false elements
  227. are encountered.
  228. Can be used with filter or itertools.ifilter, for example:
  229. >>> import itertools
  230. >>> sampleData = ['string 1', 'string 2', '', 'string 3', '', 'string 4', '', '', 'string 5']
  231. >>> first = itertools.takewhile(LessThanNBlanks(2), sampleData)
  232. >>> tuple(first)
  233. ('string 1', 'string 2', '', 'string 3')
  234. >>> first = itertools.takewhile(LessThanNBlanks(3), sampleData)
  235. >>> tuple(first)
  236. ('string 1', 'string 2', '', 'string 3', '', 'string 4')
  237. """
  238. def __init__(self, nBlanks):
  239. self.limit = nBlanks
  240. self.count = 0
  241. def __call__(self, arg):
  242. self.count += not arg
  243. if self.count > self.limit:
  244. raise ValueError("Should not call this object anymore.")
  245. return self.count < self.limit
  246. class LessThanNConsecutiveBlanks(object):
  247. """
  248. An object that when called will return True until n consecutive
  249. false elements are encountered.
  250. Can be used with filter or itertools.ifilter, for example:
  251. >>> import itertools
  252. >>> sampleData = ['string 1', 'string 2', '', 'string 3', '', 'string 4', '', '', 'string 5']
  253. >>> first = itertools.takewhile(LessThanNConsecutiveBlanks(2), sampleData)
  254. >>> tuple(first)
  255. ('string 1', 'string 2', '', 'string 3', '', 'string 4', '')
  256. """
  257. def __init__(self, nBlanks):
  258. self.limit = nBlanks
  259. self.count = 0
  260. self.last = False
  261. def __call__(self, arg):
  262. self.count += not arg
  263. if arg:
  264. self.count = 0
  265. self.last = operator.truth(arg)
  266. if self.count > self.limit:
  267. raise ValueError("Should not call this object anymore.")
  268. return self.count < self.limit
  269. class splitter(object):
  270. """
  271. object that will split a string with the given arguments for each call.
  272. >>> s = splitter(',')
  273. >>> list(s('hello, world, this is your, master calling'))
  274. ['hello', ' world', ' this is your', ' master calling']
  275. """
  276. def __init__(self, sep = None):
  277. self.sep = sep
  278. def __call__(self, s):
  279. lastIndex = 0
  280. while True:
  281. nextIndex = s.find(self.sep, lastIndex)
  282. if nextIndex != -1:
  283. yield s[lastIndex:nextIndex]
  284. lastIndex = nextIndex + 1
  285. else:
  286. yield s[lastIndex:]
  287. break
  288. def grouper_nofill_str(n, iterable):
  289. """
  290. Take a sequence and break it up into chunks of the specified size.
  291. The last chunk may be smaller than size.
  292. This works very similar to grouper_nofill, except
  293. it works with strings as well.
  294. >>> tuple(grouper_nofill_str(3, 'foobarbaz'))
  295. ('foo', 'bar', 'baz')
  296. You can still use it on non-strings too if you like.
  297. >>> tuple(grouper_nofill_str(42, []))
  298. ()
  299. >>> tuple(grouper_nofill_str(3, list(range(10))))
  300. ([0, 1, 2], [3, 4, 5], [6, 7, 8], [9])
  301. """
  302. res = more.chunked(iterable, n)
  303. if isinstance(iterable, six.string_types):
  304. res = (''.join(item) for item in res)
  305. return res
  306. def infiniteCall(f, *args):
  307. "Perpetually yield the result of calling function f."
  308. while True:
  309. yield f(*args)
  310. class Counter(object):
  311. """
  312. Wrap an iterable in an object that stores the count of items
  313. that pass through it.
  314. >>> items = Counter(range(20))
  315. >>> values = list(items)
  316. >>> items.count
  317. 20
  318. """
  319. def __init__(self, i):
  320. self.count = 0
  321. self._orig_iter = iter(i)
  322. def __iter__(self):
  323. return self
  324. def __next__(self):
  325. result = next(self._orig_iter)
  326. self.count += 1
  327. return result
  328. next = __next__
  329. def GetCount(self):
  330. warnings.warn("Use count attribute directly", DeprecationWarning)
  331. return self.count
  332. # todo, factor out caching capability
  333. class iterable_test(dict):
  334. """
  335. Test objects for iterability, caching the result by type
  336. >>> test = iterable_test()
  337. >>> test['foo']
  338. False
  339. >>> test[[]]
  340. True
  341. """
  342. def __init__(self, ignore_classes=six.string_types+(six.binary_type,)):
  343. """ignore_classes must include str, because if a string
  344. is iterable, so is a single character, and the routine runs
  345. into an infinite recursion"""
  346. assert set(six.string_types) <= set(ignore_classes), (
  347. 'str must be in ignore_classes')
  348. self.ignore_classes = ignore_classes
  349. def __getitem__(self, candidate):
  350. return dict.get(self, type(candidate)) or self._test(candidate)
  351. def _test(self, candidate):
  352. try:
  353. if isinstance(candidate, tuple(self.ignore_classes)):
  354. raise TypeError
  355. iter(candidate)
  356. result = True
  357. except TypeError:
  358. result = False
  359. self[type(candidate)] = result
  360. return result
  361. def iflatten(subject, test=None):
  362. if test is None:
  363. test = iterable_test()
  364. if not test[subject]:
  365. yield subject
  366. else:
  367. for elem in subject:
  368. for subelem in iflatten(elem, test):
  369. yield subelem
  370. def flatten(subject, test=None):
  371. """
  372. Flatten an iterable with possible nested iterables.
  373. Adapted from
  374. http://mail.python.org/pipermail/python-list/2003-November/233971.html
  375. >>> flatten(['a','b',['c','d',['e','f'],'g'],'h'])
  376. ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
  377. Note this will normally ignore string types as iterables.
  378. >>> flatten(['ab', 'c'])
  379. ['ab', 'c']
  380. Same for bytes
  381. >>> flatten([b'ab', b'c'])
  382. [b'ab', b'c']
  383. """
  384. return list(iflatten(subject, test))
  385. def empty():
  386. """
  387. An empty iterator.
  388. """
  389. return iter(tuple())
  390. def is_empty(iterable):
  391. """
  392. Return whether the iterable is empty or not. Consumes at most one item
  393. from the iterator to test.
  394. >>> is_empty(iter(range(0)))
  395. True
  396. >>> is_empty(iter(range(1)))
  397. False
  398. """
  399. try:
  400. next(iter(iterable))
  401. except StopIteration:
  402. return True
  403. return False
  404. class Reusable(object):
  405. """
  406. An iterator that may be reset and reused.
  407. >>> ri = Reusable(range(3))
  408. >>> tuple(ri)
  409. (0, 1, 2)
  410. >>> next(ri)
  411. 0
  412. >>> tuple(ri)
  413. (1, 2)
  414. >>> next(ri)
  415. 0
  416. >>> ri.reset()
  417. >>> tuple(ri)
  418. (0, 1, 2)
  419. """
  420. def __init__(self, iterable):
  421. self.__saved = iterable
  422. self.reset()
  423. def __iter__(self): return self
  424. def reset(self):
  425. """
  426. Resets the iterator to the start.
  427. Any remaining values in the current iteration are discarded.
  428. """
  429. self.__iterator, self.__saved = itertools.tee(self.__saved)
  430. def __next__(self):
  431. try:
  432. return next(self.__iterator)
  433. except StopIteration:
  434. # we're still going to raise the exception, but first
  435. # reset the iterator so it's good for next time
  436. self.reset()
  437. raise
  438. next = __next__
  439. def every_other(iterable):
  440. """
  441. Yield every other item from the iterable
  442. >>> ' '.join(every_other('abcdefg'))
  443. 'a c e g'
  444. """
  445. items = iter(iterable)
  446. while True:
  447. yield next(items)
  448. next(items)
  449. def remove_duplicates(iterable, key=None):
  450. """
  451. Given an iterable with items that may come in as sequential duplicates,
  452. remove those duplicates.
  453. Unlike unique_justseen, this function does not remove triplicates.
  454. >>> ' '.join(remove_duplicates('abcaabbccaaabbbcccbcbc'))
  455. 'a b c a b c a a b b c c b c b c'
  456. >>> ' '.join(remove_duplicates('aaaabbbbb'))
  457. 'a a b b b'
  458. """
  459. return itertools.chain.from_iterable(six.moves.map(
  460. every_other, six.moves.map(
  461. operator.itemgetter(1),
  462. itertools.groupby(iterable, key)
  463. )))
  464. def skip_first(iterable):
  465. """
  466. Skip the first element of an iterable
  467. >>> tuple(skip_first(range(10)))
  468. (1, 2, 3, 4, 5, 6, 7, 8, 9)
  469. """
  470. return itertools.islice(iterable, 1, None)
  471. def peek(iterable):
  472. """
  473. Get the next value from an iterable, but also return an iterable
  474. that will subsequently return that value and the rest of the
  475. original iterable.
  476. >>> l = iter([1,2,3])
  477. >>> val, l = peek(l)
  478. >>> val
  479. 1
  480. >>> list(l)
  481. [1, 2, 3]
  482. """
  483. peeker, original = itertools.tee(iterable)
  484. return next(peeker), original
  485. class Peekable(object):
  486. """
  487. Wrapper for a traditional iterable to give it a peek attribute.
  488. >>> nums = Peekable(range(2))
  489. >>> nums.peek()
  490. 0
  491. >>> nums.peek()
  492. 0
  493. >>> next(nums)
  494. 0
  495. >>> nums.peek()
  496. 1
  497. >>> next(nums)
  498. 1
  499. >>> nums.peek()
  500. Traceback (most recent call last):
  501. ...
  502. StopIteration
  503. Peekable should accept an iterable and not just an iterator.
  504. >>> list(Peekable(range(2)))
  505. [0, 1]
  506. """
  507. def __new__(cls, iterator):
  508. # if the iterator is already 'peekable', return it; otherwise
  509. # wrap it
  510. if hasattr(iterator, 'peek'):
  511. return iterator
  512. else:
  513. return object.__new__(cls)
  514. def __init__(self, iterator):
  515. self.iterator = iter(iterator)
  516. def __iter__(self):
  517. return self
  518. def __next__(self):
  519. return next(self.iterator)
  520. next = __next__
  521. def peek(self):
  522. result, self.iterator = peek(self.iterator)
  523. return result
  524. def takewhile_peek(predicate, iterable):
  525. """
  526. Like takewhile, but takes a peekable iterable and doesn't
  527. consume the non-matching item.
  528. >>> items = Peekable(range(10))
  529. >>> is_small = lambda n: n < 4
  530. >>> small_items = takewhile_peek(is_small, items)
  531. >>> list(small_items)
  532. [0, 1, 2, 3]
  533. >>> list(items)
  534. [4, 5, 6, 7, 8, 9]
  535. """
  536. while True:
  537. if not predicate(iterable.peek()):
  538. break
  539. yield next(iterable)
  540. def first(iterable):
  541. """
  542. Return the first item from the iterable.
  543. >>> first(range(11))
  544. 0
  545. >>> first([3,2,1])
  546. 3
  547. >>> iter = range(11)
  548. >>> first(iter)
  549. 0
  550. """
  551. iterable = iter(iterable)
  552. return next(iterable)
  553. def last(iterable):
  554. """
  555. Return the last item from the iterable, discarding the rest.
  556. >>> last(range(20))
  557. 19
  558. >>> last([])
  559. Traceback (most recent call last):
  560. ...
  561. ValueError: Iterable contains no items
  562. """
  563. for item in iterable:
  564. pass
  565. try:
  566. return item
  567. except NameError:
  568. raise ValueError("Iterable contains no items")
  569. def one(item):
  570. """
  571. Return the first element from the iterable, but raise an exception
  572. if elements remain in the iterable after the first.
  573. >>> one(['val'])
  574. 'val'
  575. >>> one(['val', 'other'])
  576. Traceback (most recent call last):
  577. ...
  578. ValueError: ...values to unpack...
  579. >>> one([])
  580. Traceback (most recent call last):
  581. ...
  582. ValueError: ...values to unpack...
  583. >>> numbers = itertools.count()
  584. >>> one(numbers)
  585. Traceback (most recent call last):
  586. ...
  587. ValueError: ...values to unpack...
  588. >>> next(numbers)
  589. 2
  590. """
  591. result, = item
  592. return result
  593. def nwise(iter, n):
  594. """
  595. Like pairwise, except returns n-tuples of adjacent items.
  596. s -> (s0,s1,...,sn), (s1,s2,...,s(n+1)), ...
  597. """
  598. iterset = [iter]
  599. while len(iterset) < n:
  600. iterset[-1:] = itertools.tee(iterset[-1])
  601. next(iterset[-1], None)
  602. return six.moves.zip(*iterset)
  603. def window(iter, pre_size=1, post_size=1):
  604. """
  605. Given an iterable, return a new iterable which yields triples of
  606. (pre, item, post), where pre and post are the items preceeding and
  607. following the item (or None if no such item is appropriate). pre
  608. and post will always be pre_size and post_size in length.
  609. >>> example = window(range(10), pre_size=2)
  610. >>> pre, item, post = next(example)
  611. >>> pre
  612. (None, None)
  613. >>> post
  614. (1,)
  615. >>> next(example)
  616. ((None, 0), 1, (2,))
  617. >>> list(example)[-1]
  618. ((7, 8), 9, (None,))
  619. """
  620. pre_iter, iter = itertools.tee(iter)
  621. pre_iter = itertools.chain((None,) * pre_size, pre_iter)
  622. pre_iter = nwise(pre_iter, pre_size)
  623. post_iter, iter = itertools.tee(iter)
  624. post_iter = itertools.chain(post_iter, (None,) * post_size)
  625. post_iter = nwise(post_iter, post_size)
  626. next(post_iter, None)
  627. return six.moves.zip(pre_iter, iter, post_iter)
  628. class IterSaver(object):
  629. def __init__(self, n, iterable):
  630. self.n = n
  631. self.iterable = iterable
  632. self.buffer = collections.deque()
  633. def __next__(self):
  634. while len(self.buffer) <= self.n:
  635. self.buffer.append(next(self.iterable))
  636. return self.buffer.popleft()
  637. next = __next__
  638. def partition_items(count, bin_size):
  639. """
  640. Given the total number of items, determine the number of items that
  641. can be added to each bin with a limit on the bin size.
  642. So if you want to partition 11 items into groups of 3, you'll want
  643. three of three and one of two.
  644. >>> partition_items(11, 3)
  645. [3, 3, 3, 2]
  646. But if you only have ten items, you'll have two groups of three and
  647. two of two.
  648. >>> partition_items(10, 3)
  649. [3, 3, 2, 2]
  650. """
  651. num_bins = int(math.ceil(count / float(bin_size)))
  652. bins = [0] * num_bins
  653. for i in range(count):
  654. bins[i % num_bins] += 1
  655. return bins
  656. def balanced_rows(n, iterable, fillvalue=None):
  657. """
  658. Like grouper, but balance the rows to minimize fill per row.
  659. balanced_rows(3, 'ABCDEFG', 'x') --> ABC DEx FGx"
  660. """
  661. iterable, iterable_copy = itertools.tee(iterable)
  662. count = len(tuple(iterable_copy))
  663. for allocation in partition_items(count, n):
  664. row = itertools.islice(iterable, allocation)
  665. if allocation < n:
  666. row = itertools.chain(row, [fillvalue])
  667. yield tuple(row)
  668. def reverse_lists(lists):
  669. """
  670. >>> reverse_lists([[1,2,3], [4,5,6]])
  671. [[3, 2, 1], [6, 5, 4]]
  672. """
  673. return list(map(list, map(reversed, lists)))
  674. def always_iterable(item):
  675. """
  676. Given an object, always return an iterable. If the item is not
  677. already iterable, return a tuple containing only the item. If item is
  678. None, an empty iterable is returned.
  679. >>> always_iterable([1,2,3])
  680. [1, 2, 3]
  681. >>> always_iterable('foo')
  682. ('foo',)
  683. >>> always_iterable(None)
  684. ()
  685. >>> always_iterable(range(10))
  686. range(0, 10)
  687. >>> def _test_func(): yield "I'm iterable"
  688. >>> print(next(always_iterable(_test_func())))
  689. I'm iterable
  690. """
  691. if item is None:
  692. item = ()
  693. if isinstance(item, six.string_types) or not hasattr(item, '__iter__'):
  694. item = item,
  695. return item
  696. def suppress_exceptions(callables, *exceptions):
  697. """
  698. Call each callable in callables, suppressing any exceptions supplied. If
  699. no exception classes are supplied, all Exceptions will be suppressed.
  700. >>> import functools
  701. >>> c1 = functools.partial(int, 'a')
  702. >>> c2 = functools.partial(int, '10')
  703. >>> list(suppress_exceptions((c1, c2)))
  704. [10]
  705. >>> list(suppress_exceptions((c1, c2), KeyError))
  706. Traceback (most recent call last):
  707. ...
  708. ValueError: invalid literal for int() with base 10: 'a'
  709. """
  710. if not exceptions:
  711. exceptions = Exception,
  712. for callable in callables:
  713. try:
  714. yield callable()
  715. except exceptions:
  716. pass
  717. def apply(func, iterable):
  718. """
  719. Like 'map', invoking func on each item in the iterable,
  720. except return the original item and not the return
  721. value from the function.
  722. Useful when the side-effect of the func is what's desired.
  723. >>> res = apply(print, range(1, 4))
  724. >>> list(res)
  725. 1
  726. 2
  727. 3
  728. [1, 2, 3]
  729. """
  730. for item in iterable:
  731. func(item)
  732. yield item
  733. def list_or_single(iterable):
  734. """
  735. Given an iterable, return the items as a list. If the iterable contains
  736. exactly one item, return that item. Correlary function to always_iterable.
  737. >>> list_or_single(iter('abcd'))
  738. ['a', 'b', 'c', 'd']
  739. >>> list_or_single(['a'])
  740. 'a'
  741. """
  742. result = list(iterable)
  743. if len(result) == 1:
  744. result = result[0]
  745. return result