2015-07-22 2 views
0

мне удалось изменить рецепт roundrobin в https://docs.python.org/3.1/library/itertools.html
включить ограничение (остановка при достижении X элементов) - код ниже ...питона itertools круговой, без дупликации

Теперь - то, что я действительно хочу «остановитесь при достижении элементов X, но без дублирования элементов».
Возможно ли это? (Потому что это генератор ...)

def roundrobin(limit, *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() 
       limit -= 1 
       if limit == 0: 
        return 

     except StopIteration: 
      pending -= 1 
      nexts = cycle(islice(nexts, pending)) 

называя его:

candidates = [['111', '222', '333'],['444','222','555']] 
list(roundrobin(4, *candidates)) 

Я хотел бы получить:

['111,'444','222','333'] 

и нет:

['111,'444','222','222'] 

как я получаю с текущим кодом

+0

Да, конечно, это возможно. Добавьте 'set', чтобы отслеживать элементы, полученные до сих пор. – jonrsharpe

+0

но ограничение - внутренний. Предположим, что у меня есть повторение, я хочу, чтобы округлый «знал», чтобы дать еще один ... – Boaz

+0

Это прекрасно - только декремент 'limit', когда вы« сдаете ». Обратите внимание, что вы можете использовать 'while pending and limit', а не явно проверять' limit == 0'. – jonrsharpe

ответ

1

Вот одна из возможных реализаций - я добавил set, названный seen, внутри функции генератора, чтобы отслеживать элементы, которые у нас уже есть yield ред. Обратите внимание, что это означает, что все элементов каждыйiterableдолжны быть hashable (если они получают достигнуты), который не является ограничение базы roundrobin.

def roundrobin_limited_nodupe(limit, *iterables): 
    """A round-robin iterator duplicates removed and a limit. 

     >>> list(roundrobin_limited_nodupe(6, 'ABC', 'DB', 'EFG')) 
     ['A', 'D', 'E', 'B', 'F', 'C'] # only six elements, only one 'B' 

    Notes: 
     - Recipe credited to George Sakkis 

    """ 
    pending = len(iterables) 
    seen = set() # keep track of what we've seen 
    nexts = cycle(iter(it).next for it in iterables) 
    while pending: 
     try: 
      for next in nexts: 
       candidate = next() 
       if candidate not in seen: # only yield when it's new 
        seen.add(candidate) 
        yield candidate 
        limit -= 1 
        if limit == 0: 
         return 
     except StopIteration: 
      pending -= 1 
      nexts = cycle(islice(nexts, pending)) 
+0

набор внутри ... Ну, я думал, что есть что-то более сложное делать :) Спасибо – Boaz

+0

@ Повсюду недостаток в том, что 'set' будет продолжать увеличиваться, что может быть проблемой памяти с большим количеством больших' iterables ', но это должно быть довольно эффективно в противном случае. – jonrsharpe

+1

просто быстро исправить (если кто-то попадет сюда для справки) - кандидат на получение должен быть до предела - = 1, иначе мы не получим последний – Boaz

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