2015-04-30 2 views
1

Вот пример:Переменных и перебор кратных итераторов различной длины без остановки

for i in f('abcde','fg','hijk'): 
print(i,end='') 
#should print out 
afhbgicjdke 

Вот то, что я до сих пор:

def f(*args): 
    arg_list = [argument for argument in args] 
    iter_list = [] 
    for arg in arg_list: 
     iter_list.append(iter(arg)) 

    try: 
     while True: 
      for i in iter_list: 
       yield next(i) 
    except StopIteration: 
     iter_list.remove(i) 
     for i in reversed(iter_list): 
      yield next(i) 

С тем же примером этого является то, что я распечатка:

afhbgicjd 

Я не могу понять, как справиться с этой ошибкой StopIteration. Я пытаюсь реализовать это без использования itertools

ответ

2

Это приложение для izip_longest.

from itertools import chain, izip_longest 
''.join(chain.from_iterable(izip_longest('abcde', 'fg', 'hijk', fillvalue=''))) 

Выход:

'afhbgicjdke' 

В этом примере заархивированы три последовательностей в наборы из трех элементов. Если для одной из наших последовательностей не было соответствующего элемента, мы использовали значение по умолчанию ''. Затем мы сгладили эти кортежи, используя chain.from_iterable, и мы, наконец, присоединились ко всем персонажам.

Если разрешено использовать только основные функции, мы могли бы сделать это следующим образом:

def f(*args): 
    n = len(args) 
    iters = map(iter, args) 
    exhausted = [False] * n 
    while n > 0: 
     for i, it in enumerate(iters): 
      if not exhausted[i]: 
       try: 
        yield next(it) 
       except StopIteration: 
        exhausted[i] = True 
        n -= 1 

print ''.join(f('abcde', 'fg', 'hijk')) 

С помощью этого кода мы отслеживаем истощенных итераторы. Когда число в реальном времени достигает, мы останавливаем наш генератор. Если итератор исчерпан, мы не будем проверять его в следующий раз.

+0

Я пытаюсь реализовать это без itertools – dustinyourface

+0

dustinyourface: В Python 3, это называется 'zip_longest()'. [Documentation] (https://docs.python.org/3/library/itertools.html#itertools.zip_longest) предоставляет чистый эквивалент Python (так же как и документация Python 2 для 'izip_longest()'. То же самое для 'chain()'. – martineau

+0

@ dustinyourface Я обновил свой ответ – JuniorCompressor

2

Простое решение, которое не использует itertools или проносясь (а также не пытаться вставлять сжать реализацию):

def f (*args): 
    maxLen = max(map(len, args)) 
    for i in range(maxLen): 
     for arg in args: 
      if i < len(arg): 
       yield arg[i] 

Для любой итерации:

def f (*args): 
    args = [iter(arg) for arg in args] 
    while True: 
     yielded = False 
     for arg in args: 
      x = next(arg, None) 
      if x is not None: 
       yielded = True 
       yield x 
     if not yielded: 
      break 
>>> list(f(range(3), range(3, 5), range(5, 10))) 
[0, 3, 5, 1, 4, 6, 2, 7, 8, 9] 
+0

Это не дает значений в желаемом порядке. – martineau

+0

Спасибо, что эта информация была полезной, но я пытаюсь чередовать. См. Пример. – dustinyourface

+1

К сожалению, я не правильно читал вопрос. Изменен мой ответ. – poke

0

Это a recipe in the itertools documentation

def roundrobin(*iterables): 
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C" 
    # Recipe credited to George Sakkis 
    pending = len(iterables) 
    nexts = cycle(iter(it).next for it in iterables) 
    while pending: 
     try: 
      for next in nexts: 
       yield next() 
     except StopIteration: 
      pending -= 1 
      nexts = cycle(islice(nexts, pending)) 

Например, с помощью IPython REPL:

In [19]: from itertools import * 

In [20]: def roundrobin(*iterables): 
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C" 
    # Recipe credited to George Sakkis 
    pending = len(iterables) 
    nexts = cycle(iter(it).next for it in iterables) 
    while pending: 
     try: 
      for next in nexts: 
       yield next() 
     except StopIteration: 
      pending -= 1 
      nexts = cycle(islice(nexts, pending)) 
    ....:      

In [21]: "afhbgicjdke" == "".join(roundrobin('abcde','fg','hijk')) 
Out[21]: True 
+0

Я увидел в комментарии к ответу, что ОП пытается не использовать 'itertools' ... Сказав, что надлежащее место для такого утверждения является телом вопроса (или, может быть, самим вопросом), я не 't удаляю мой ответ, поскольку я рассматриваю его как своего рода почтовый адрес, указывающий на отличную документацию «itertools» и большое количество рецептов, которые были собраны там. – gboffi

Смежные вопросы