Все, кроме последних N элементов итератора в Python - PullRequest
6 голосов
/ 09 июля 2011

Каков наилучший способ получить все, кроме последних N элементов итератора в Python? Вот пример этого в теоретическом действии:

>>> list(all_but_the_last_n(range(10), 0))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(all_but_the_last_n(range(10), 2))
[0, 1, 2, 3, 4, 5, 6, 7]

Ответы [ 6 ]

6 голосов
/ 09 июля 2011

Просто для удовольствия, вот вариант решения Игнасио, который не требует deque.

>>> def truncate(it, n):
...     cache = [next(it) for i in range(n)]
...     index = 0
...     for val in it:
...         val, cache[index] = cache[index], val
...         index = (index + 1) % n
...         yield val

Меня не особенно волновала скорость, когда я писал выше ... но, возможно, это было бы немного быстрее:

def truncate(it, n):
    cache = [next(it) for i in range(n)]
    index = 0
    for val in it:
        yield cache[index]
        cache[index] = val
        index = (index + 1) % n
5 голосов
/ 09 июля 2011

Используйте collections.deque. Нажмите N элементы из источника при первом вызове. При каждом последующем вызове извлекайте элемент, вставляйте элемент из источника и получайте извлеченный элемент.

3 голосов
/ 09 июля 2011

Основываясь на описании Игнасио Васкеса-Абрамса:

from collections import deque

def all_but_the_last_n(iterable, count):
    q = deque()
    i = iter(iterable)
    for n in range(count):
        q.append(i.next())
    for item in i:
        q.append(item)
        yield q.popleft()

Я задавался вопросом, лучше ли использовать деку справа налево (аппенд, поплефт) или слева направо (аппендифт, поп).Так что я рассчитал это с python 2.5.2 и обнаружил, что rtl был 3.59 usec, в то время как ltr был 3.53 usec.Разница 0.06 usec незначительна.тест состоял в том, чтобы добавить один элемент и вытолкнуть один элемент.

1 голос
/ 05 февраля 2014

Для списка вы можете сделать это:

def all_but_the_last_n(aList, N):
    return aList[:len(aList) - N]

myList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
N = 4

print(all_but_the_last_n(myList, N))

Напечатает:

[0, 1, 2, 3, 4, 5]
1 голос
/ 09 июля 2011

Использование решения Игнасио.

import collections
def all_but_the_last_n(iterable, n):
    it = iter(iterable)
    fifo = collections.deque()
    for _, i in zip(range(n), it):
        fifo.append(i)
    for i in it:
        fifo.append(i)
        yield fifo.popleft()

print(list(all_but_the_last_n(range(10), 3)))
print(list(all_but_the_last_n('abcdefghijkl', 3)))

К сожалению, collections не имеет циклического буфера. Это было бы более эффективно с точки зрения пропуска кэша с одним.

0 голосов
/ 20 февраля 2019

Это компактно (кроме consume рецепта, взятого из itertools рецептов) и должно работать со скоростью C:

import collections
import operator
from itertools import islice, tee


def truncate(iterable, n):
    a, b = tee(iterable)
    consume(b, n)
    return map(operator.itemgetter(0), zip(a, b))


# From itertools recipes
def consume(iterator, n=None):
    "Advance the iterator n-steps ahead. If n is None, consume entirely."
    # Use functions that consume iterators at C speed.
    if n is None:
        # feed the entire iterator into a zero-length deque
        collections.deque(iterator, maxlen=0)
    else:
        # advance to the empty slice starting at position n
        next(islice(iterator, n, n), None)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...