python / cpython

The Python programming language
https://www.python.org
Other
63.15k stars 30.24k forks source link

splice() function for itertools #45226

Closed 924bf1df-39a3-493d-b8d5-aeacc132c84f closed 17 years ago

924bf1df-39a3-493d-b8d5-aeacc132c84f commented 17 years ago
BPO 1757395
Nosy @rhettinger

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields: ```python assignee = None closed_at = created_at = labels = ['type-feature', 'library'] title = 'splice() function for itertools' updated_at = user = 'https://bugs.python.org/asdutton' ``` bugs.python.org fields: ```python activity = actor = 'rhettinger' assignee = 'none' closed = True closed_date = None closer = None components = ['Library (Lib)'] creation = creator = 'asdutton' dependencies = [] files = [] hgrepos = [] issue_num = 1757395 keywords = [] message_count = 3.0 messages = ['55148', '55149', '55150'] nosy_count = 2.0 nosy_names = ['rhettinger', 'asdutton'] pr_nums = [] priority = 'normal' resolution = 'rejected' stage = None status = 'closed' superseder = None type = 'enhancement' url = 'https://bugs.python.org/issue1757395' versions = ['Python 2.6'] ```

924bf1df-39a3-493d-b8d5-aeacc132c84f commented 17 years ago

Could we have a splice function in itertools? I see there was once a roundrobin proposal (bpo-756253), but it was three years ago ...

Here's an alternate implementation:

def splice(*args):
  """splice(*iterables) --> iterator
  Returns an iterator whose next() method returns an element from each of the iterables in turn before starting again with the first iterable."""
  iters = list(args)
  n = len(iters)
  i = 0
  while n>0:
    i %= n
    try:
      yield iters[i].next()
      i += 1
    except StopIteration, e:
      n -= 1
      iters[i:i+1] = []
  raise StopIteration
rhettinger commented 17 years ago

The reasons for rejecting the roundrobin proposal still apply three years later. It is somewhat use case challenged.

FWIW, there is a reasonably efficient pure python implementation using collections.deque(). See http://docs.python.org/lib/deque-recipes.html for an unoptimized recipe which can be fine-tuned to use bound methods and all local variables for better speed.

rhettinger commented 17 years ago

FWIW, here is the optimized recipe:

def roundrobin(*iterables):
    pending = deque(iter(i).next for i in reversed(iterables))
    rotate, pop, _StopIteration = pending.rotate, pending.pop, StopIteration
    while pending:
        try:
            while 1:
                yield pending[-1]()
                rotate()
        except _StopIteration:
            pop()