2016-12-20 3 views
2

У меня есть тысячи идентификаторов, извлеченных из файла CSV (теперь это генератор идентификаторов) для повторения и обработки этих идентификаторов.Избегайте сплиттера генератора, чтобы произвести Нет значений

Для оптимизации кода я сгруппировал эти идентификаторы в партии и обрабатывал всю партию за раз.

Следующий код разделяет генератор на размер партии n.

from itertools import zip_longest 
def grouper(n, iterable): 
    """ Grouping of iterable with n objects 
     Attributes 
     :n No. of values in a group 
     :iterable/string to be iterated 
     :return group of string/iterator values 
    "grouper(3, 'abcdefg') --> ('a','b','c'), ('d','e','f'), ('g',None, None)" 
    """ 
    return zip_longest(*[iter(iterable)]*n) 

например:

>>>acc_ids = ['ID21', 'ID24', 'ID38', 'ID40', 'ID42', 'ID43', 'ID47', 'ID54', 'ID58'] 
#--As an iterator 
>>>id_generator = (i for i in acc_ids) 
>>>batches = grouper(7, id_generator) 
>>>batches 
<itertools.zip_longest object at 0x7f3beb3313b8> 
#This iterator is much similar to the below list and notice padded `None`(s) at the end of last batch: 
#[('ID21', 'ID24', 'ID38', 'ID40', 'ID42', 'ID43', 'ID47'), ('ID54', 'ID58', None, None, None, None, None)] 

Вот проблема, чтобы удалить мягкие None значения из итератора Я использую filter

for batch in batches: 
    batch = list(filter(None, batch)) 

Этот фильтр удаляет None значения из списка , Так как я имею в виду, вместо того, чтобы добавлять дополнительный фильтр, мы можем предотвратить производить мягкие None значения, а разделив генератор ...

запросов:

  • есть ли другой подход разделить большой генератор для производства пакеты без добавления Нет/Нулевые значения в конце последней партии.
    OR
  • Можем ли мы изменить выше функцию grouper для подавления производства пропущенных значений Нет?
+1

* «Но этот фильтр возвращает мне список» *, в Python 3 он не возвращает список, возвращается объект 'filter'. –

+0

Документы 'filter' в Python 3« Верните итератор, уступающий этим элементам итерабельного ... » –

+0

@ JimFasarakis-Hilliard: Извините, похоже, что я преобразовал его в список, чтобы запустить вызов HTTP API, я обновлю вопрос, который я просто хочу удалить пропущенные значения None.и нужно избегать использования фильтра –

ответ

3

Это может работать для вас:

def grouper(n, iterable): 
    iter_ = iter(iterbale) 
    while True: 
     res = tuple(next(iter_) for _ in range(n)) 
     if not res: 
      return 
     yield res 


acc_ids = ['ID21', 'ID24', 'ID38', 'ID40', 'ID42', 'ID43', 'ID47', 'ID54', 'ID58'] 
id_generator = iter(acc_ids) 
batches = grouper(7, id_generator) 
print(list(batches)) 

Выход:

[('ID21', 'ID24', 'ID38', 'ID40', 'ID42', 'ID43', 'ID47'), ('ID54', 'ID58')] 
+0

Это работает для вас? –

+0

Вместо 'raise StopIteration' было бы лучше« возвратиться »(да, просто не возвращай ничего). 'Raise StopIteration' устарел для (вероятно, хороших) причин. – MSeifert

+0

@MSeifert Да, выглядит немного приятнее. Изменено. Благодарю. –

1

Одна возможность состоит в том, чтобы использовать внешнюю библиотеку, которая уже включает в себя такую ​​функцию:

  • iteration_utilities.grouper:

    >>> from iteration_utilities import grouper 
    >>> list(grouper(acc_ids, 7)) 
    [('ID21', 'ID24', 'ID38', 'ID40', 'ID42', 'ID43', 'ID47'), ('ID54', 'ID58')] 
    
  • more-itertools.chunked:

    >>> from more_itertools import chunked 
    >>> list(chunked(acc_ids, 7)) 
    [['ID21', 'ID24', 'ID38', 'ID40', 'ID42', 'ID43', 'ID47'], ['ID54', 'ID58']] 
    
  • pytoolz.partition_all или cytoolz.partition_all:

    >>> from toolz import partition_all 
    >>> list(partition_all(7, acc_ids)) 
    [('ID21', 'ID24', 'ID38', 'ID40', 'ID42', 'ID43', 'ID47'), ('ID54', 'ID58')] 
    

Эти библиотеки все либеральные лицензии (Apache, MIT и BSD), так что даже если вы не» t хотите, чтобы вы могли просто повторно использовать свой код (вам может потребоваться включить свою лицензию в ваш c однако, см. их лицензии для получения дополнительной информации).

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