2015-04-28 3 views
-2

Мой профессор хочет, чтобы мы записали генератор, который принимает аргументы * args в качестве аргумента и дает первое значение 1-го аргумента, затем 1-е значение 2-го, а затем 1-го из 3-го. И когда это будет сделано, это даст 2-ое значение 1-го, 2-го значения 2-го и т. Д.Генератор переменного тока

У меня возникают проблемы с повторением итераций, потому что они имеют разную длину. Таким образом, хотя один итерабельный может иметь длину 4, другой может иметь длину 2 и поэтому пытается получить третье значение обоих результатов в ошибке.

Я хочу, чтобы генератор остановил момент, когда он столкнулся с аргументом, который закончился из-за значений для перебора.

Edit: Это то, что я до сих пор ...

temp = list(args) 
while True: 
    for x in range(len(temp)): 
     for letters in args: 
      yield next(letters) 

Сейчас это дает мне Тип ошибки: «ул» объект не итератора При попытке запуска этой линии .. .

[print(i) for i in alternate('abcde', 'fg', 'hijk')] 

Я не разрешается использовать почтовый или любой другой импорт.

Функция может принимать строки и итерируемых в качестве параметра

+0

" Мне не разрешено использовать zip или любой другой импорт ». 'zip()' является встроенным, а не импортом. Это все еще запрещено? – TigerhawkT3

ответ

1

Вы можете использовать комбинацию izip и chain от itertools:

from itertools import izip, chain 

def foo(*iters): 
    return chain.from_iterable(izip(*iters)) 

for bar in foo([1, 2], [3, 4, 5], [6, 7]): 
    print bar 

Результат:

1 
3 
6 
2 
4 
7 

В этом пример izip(*iters) вернет итерат или который генерирует:

(1, 3, 6) 
(2, 4, 7) 

Значение 5 не будет сгенерирован так izip остановки, когда человек итератора был исчерпан. chain.from_iterable будет рассматривать каждый кортеж как итератор чисел, и он будет связывать все эти значения вместе.

EDIT

С zip не допускается, мы можем обеспечить собственную реализацию, которая основана на коде, предоставленной из itertools страницы:

def foo(*iters): 
    iterators = map(iter, iters) 
    while iterators: 
     for v in map(next, iterators): 
      yield v 
+0

отличный ответ :) вы побеждаете ... к сожалению, это сломает ему голову ... (и 'izip_longest' может быть более уместным ... .комбинация с фильтром (None, ...)' –

+0

Спасибо за ответ , но, к сожалению, я не могу использовать zip в своем решении. – FlyingBumble

+0

@Xari почему бы и нет? zip - это то, как вы должны это делать /// (и я оттягиваю свое предыдущее заявление об изипе, которое больше всего теперь, когда я перечитываю OP) –

0

Использование zip():

>>> def mygen(*args): 
...  for i in zip(*args): 
...    for j in i: 
...      yield j 
... 
>>> a = mygen('abcde', 'fg', 'hijk') 
>>> next(a) 
'a' 
>>> next(a) 
'f' 
>>> next(a) 
'h' 
>>> next(a) 
'b' 
>>> next(a) 
'g' 
>>> next(a) 
'i' 
>>> next(a) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
StopIteration 
1

Я закончил решение проблемы (без использования zip, так как я не был разрешено).

temp = [iter(arg) for arg in args] 
while True: 
    for x in range(len(temp)): 
     for letters in temp: 
      yield next(letters) 

Я использовал список понимание, чтобы создать список всех аргументов, в то время как добавление всех из них, как итерируемых. Впоследствии я просто использовал цикл while, повторяя каждое значение в списке несколько раз, пока не закончил итерации. Как только он обнаружил, что больше нечего перебирать, он вышел из цикла.

+0

O теперь я вижу, что вы отправляете вопрос, чтобы вы могли ответить на него ... хорошо +1 от меня это довольно элегантное решение ... хотя вам действительно нужно просто перебирать temp вместо своих индексов 'для t в temp: для букв в t: ...' –

+1

Нужна адаптация ... Если вы не дадите аргументы, он войдет в бесконечный цикл – JuniorCompressor

0

здесь рекурсивное решение

def myGen(x): 
    for i in x: 
     if len(i) < 1: 
      break 
     yield i[0] 
    else: 
     for j in myGen([z[1:] for z in x]): 
      yield j 
0
def alternate(*args): 
    shortest = min(map(len, args)) 
    for i in xrange(shortest): 
     for arg in args: 
      yield arg[i] 

for i in alternate('abcde', 'fg', 'hijk'): 
    print i 

Выход:

a 
f 
h 
b 
g 
i 
0

Xari, вы на самом деле не нужно внешнее для цикла, например for x in range(len(temp)):

def alternate2(*args): 
    if len(args) == 0: 
     return 
    temp = [iter(arg) for arg in args] 
    while True: 
     for letters in temp: 
      yield next(letters)