Python-эквивалент Ruby's each_slice (count) - PullRequest
6 голосов
/ 30 сентября 2010

Что такое питоны, эквивалентные Ruby's each_slice(count)?
Я хочу взять 2 элемента из списка для каждой итерации.
Как и для [1,2,3,4,5,6] Я хочу обработать 1,2 в первой итерации, затем 3,4затем 5,6.
Конечно, существует обходной путь с использованием значений индекса.Но есть ли прямая функция или как-то сделать это напрямую?

Ответы [ 5 ]

9 голосов
/ 30 сентября 2010

Для этого есть рецепт для этого в документации itertools , называемый группером:

from itertools import izip_longest
def grouper(n, iterable, fillvalue=None):
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

Использовать так:

>>> l = [1,2,3,4,5,6]
>>> for a,b in grouper(2, l):
>>>     print a, b

1 2
3 4
5 6
2 голосов
/ 25 ноября 2014

То же, что и у Марка, но переименовано в 'each_slice' и работает для python 2 и 3:

try:
    from itertools import izip_longest  # python 2
except ImportError:
    from itertools import zip_longest as izip_longest  # python 3

def each_slice(iterable, n, fillvalue=None):
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)
1 голос
/ 24 августа 2015

Дублирует поведение ruby ​​each_slice для небольшого конечного среза:

def each_slice(size, iterable):
    """ Chunks the iterable into size elements at a time, each yielded as a list.

    Example:
      for chunk in each_slice(2, [1,2,3,4,5]):
          print(chunk)

      # output:
      [1, 2]
      [3, 4]
      [5]
    """
    current_slice = []
    for item in iterable:
        current_slice.append(item)
        if len(current_slice) >= size:
            yield current_slice
            current_slice = []
    if current_slice:
        yield current_slice

Ответы, приведенные выше, будут дополнять последний список (т. Е. [5, None]), который в некоторых случаях может не соответствовать желаемому..

0 голосов
/ 28 декабря 2018

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

def each_slice(list: List[str], size: int):
    batch = 0
    while batch * size < len(list):
        yield list[batch * size:(batch + 1) * size]
        batch += 1   

slices = each_slice(["a", "b", "c", "d", "e", "f", "g"], 2)
print([s for s in slices])

$ [['a', 'b'], ['c', 'd'], ['e', 'f'], ['g']]

Если вам нужно, чтобы каждый срез имел размер пакета, например, Pad None или какой-либо символ по умолчанию, вы можете просто добавить код дополнения к yield.Если вы хотите вместо каждых_коннекторов, вы можете сделать это, изменив код так, чтобы он перемещался один за другим вместо пакета за пакетом.

0 голосов
/ 23 февраля 2018

Улучшение первых двух: если итерируемая нарезка не делится точно на n, последняя будет заполнена до длины n значением None. Если это вызывает ошибки при вводе, вы можете внести небольшое изменение:

def each_slice(iterable, n, fillvalue=None):
    args = [iter(iterable)] * n
    raw = izip_longest(fillvalue=fillvalue, *args)
    return [filter(None, x) for x in raw]

Имейте в виду, что это удалит ВСЕХ Ни одного из диапазона, поэтому его следует использовать только в тех случаях, когда Ни один не вызовет ошибок в будущем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...