Пропустити перший запис для циклу в python?


187

У python: Як зробити щось на кшталт:

for car in cars:
   # Skip first and last, do work for rest

4
Я новачок, але я користувався for n, i in enumerate(cars): if n!= 0: do something to i. логіка полягає в тому, що вона додає «лічильник» до кожного значення, на яке потім можна націлити, наприклад, за допомогою if n == some_value. у цьому прикладі вона зробила б щось для кожного екземпляра i, за винятком першого.
користувач1063287

Відповіді:


268

Інші відповіді працюють лише для послідовності.

Щоб пропустити перший пункт:

itercars = iter(cars)
next(itercars)
for car in itercars:
    # do work

Якщо ви хочете пропустити останнє, ви можете зробити:

itercars = iter(cars)
# add 'next(itercars)' here if you also want to skip the first
prev = next(itercars)
for car in itercars:
    # do work on 'prev' not 'car'
    # at end of loop:
    prev = car
# now you can do whatever you want to do to the last one on 'prev'

1
Дивіться також Sven Marnach «сек відповідь
AGF

2
Я виявив, що робота cars.pop (0) та cars.pop () працює добре.
dreamwork801

@ dreamwork801 Моя відповідь і Sven's, яких я посилаю в першому коментарі, працюють для будь-яких ітерабельних, навіть нескінченних, оскільки вони не потребують операції O (n) над даними до початку ітерації. Ваша пропозиція і обидві Абгіджі працюють лише для послідовностей, а не будь-яких ітерабельних.
agf

356

Щоб пропустити перший елемент в Python, ви можете просто написати

for car in cars[1:]:
    # Do What Ever you want

або пропустити останній елем

for car in cars[:-1]:
    # Do What Ever you want

Ви можете використовувати цю концепцію для будь-якої послідовності.


52
Не для всіх ітерабелів , а для всіх послідовностей .
Свен Марнах

2
Як щодо використання пам'яті? Чи зріз робить нову копію підпорядку?
Вояджер

@Voyager Так, це робить нову копію.
Шрінівас Редді Татіпарті

27

Найкращий спосіб пропустити перший предмет:

from itertools import islice
for car in islice(cars, 1, None):
    # do something

в цьому випадку islice викликається початковою точкою 1, а кінцевою точкою None, що означає кінець ітератора.

Щоб мати можливість пропустити елементи з кінця ітерабельної програми, потрібно знати її довжину (завжди можливо для списку, але не обов'язково для всього, що ви можете повторити). наприклад, islice (автомобілі, 1, len (машини) -1) пропустить перший і останній пункт у списку автомобілів.


Подивіться на відповідь Свена (недооцінена). Він охоплює пропуск довільної кількості елементів на початку та / або в кінці будь-якого ітерабельного, використовуючи isliceдосить добре, не знаючи тривалості та зберігаючи більше об'єктів у пам'яті одразу, ніж абсолютно необхідно.
agf

Відповідь Свена фактично збереже весь ітератор в пам'яті - collection.deque буде проходити через ітератор. Спробуйте зробити щось на зразок collection.deque (xrange (10000000)). Не потрібно зберігати всі вставки в пам’яті, якщо ви хочете пропустити перший предмет ...
Roee Shenberg

2
А islice- це те, що передається dequeне всій ітератору, а пропустити лише кінцеву кількість елементів. Він не зберігає весь ітератор в пам'яті.
agf

26

Ось більш загальна функція генератора, яка пропускає будь-яку кількість елементів з початку та в кінці ітерабельного:

def skip(iterable, at_start=0, at_end=0):
    it = iter(iterable)
    for x in itertools.islice(it, at_start):
        pass
    queue = collections.deque(itertools.islice(it, at_end))
    for x in it:
        queue.append(x)
        yield queue.popleft()

Приклад використання:

>>> list(skip(range(10), at_start=2, at_end=2))
[2, 3, 4, 5, 6, 7]

Ви можете додати швидкий шлях для at_end == 0.
agf

collection.deque (...) негайно пройде через ітератор. Це означає, що пропуск (xrange (10000000), 1) займе багато пам’яті, хоча це насправді не повинно.
Roee Shenberg

4
@RoeeShenberg: skip(xrange(10000000), 1)буде використовуватися at_end=0, тому параметр deque()буде islice(it, 0), який буде споживати лише нульові елементи it. Це не займе багато пам’яті.
Свен Марнах

8
for item in do_not_use_list_as_a_name[1:-1]:
    #...do whatever

3
Не використовуйте listяк ім'я змінної
Abhijit

ОП хоче лише пропустити перший елемент. чому: -1?
luke14free

6
Насправді це не зарезервовано ; ім'я listможна повторно зв'язати. Ось чому ви не повинні , а не можуть , використовувати його.
jscs

@ luke14free, питання говорить пропустити перший елемент, але його коментар до коду означає, що він дійсно хоче пропустити перший і останній.
JerseyMike

@ luke14free Ось що говорить заголовок, а не те, що він набрав всередині коду: "пропустити, якщо перший чи останній"
KurzedMetal

3

На основі відповіді @SvenMarnach, але трохи простіше і без використання deque

>>> def skip(iterable, at_start=0, at_end=0):
    it = iter(iterable)
    it = itertools.islice(it, at_start, None)
    it, it1 = itertools.tee(it)
    it1 = itertools.islice(it1, at_end, None)
    return (next(it) for _ in it1)

>>> list(skip(range(10), at_start=2, at_end=2))
[2, 3, 4, 5, 6, 7]
>>> list(skip(range(10), at_start=2, at_end=5))
[2, 3, 4]

Також зауважте, виходячи з мого timeitрезультату, це незначно швидше, ніж рішення deque

>>> iterable=xrange(1000)
>>> stmt1="""
def skip(iterable, at_start=0, at_end=0):
    it = iter(iterable)
    it = itertools.islice(it, at_start, None)
    it, it1 = itertools.tee(it)
    it1 = itertools.islice(it1, at_end, None)
    return (next(it) for _ in it1)
list(skip(iterable,2,2))
    """
>>> stmt2="""
def skip(iterable, at_start=0, at_end=0):
    it = iter(iterable)
    for x in itertools.islice(it, at_start):
        pass
    queue = collections.deque(itertools.islice(it, at_end))
    for x in it:
        queue.append(x)
        yield queue.popleft()
list(skip(iterable,2,2))
        """
>>> timeit.timeit(stmt = stmt1, setup='from __main__ import iterable, skip, itertools', number = 10000)
2.0313770640908047
>>> timeit.timeit(stmt = stmt2, setup='from __main__ import iterable, skip, itertools, collections', number = 10000)
2.9903135454296716

Використовуючи tee(), ви все ще створюєте весь список в пам'яті для генератора, правда? (ваш it1)
Jabberwockey

3

Приклад:

mylist=['one'.'two','three'.'four'.'five']
for i in mylist[1:]:
   print(i)

В індексі python починаючи з 0, ми можемо використовувати оператор нарізки для здійснення маніпуляцій в ітерації.

for i in range(1,-1):

2

Ну, ваш синтаксис насправді не Python для початку.

Ітерації в Python закінчуються вмістом контейнерів (ну, технічно це над ітераторами) із синтаксисом for item in container. У цьому випадку контейнер є carsсписком, але ви хочете пропустити перший і останній елементи, так що це означає cars[1:-1](списки python базуються на нулі, негативні числа рахуються з кінця, і :це синтаксис зрізу.

Тож хочеш

for c in cars[1:-1]:
    do something with c

4
Це не працюватиме з ітерабельним (наприклад, генератором), лише з послідовністю.
Roee Shenberg

2

Альтернативний метод:

for idx, car in enumerate(cars):
    # Skip first line.
    if not idx:
        continue
    # Skip last line.
    if idx + 1 == len(cars):
        continue
    # Real code here.
    print car

2

Ось мій кращий вибір. Для цього не потрібно додавати багато циклу і не використовує нічого, крім вбудованих інструментів.

Перейти від:

for item in my_items:
  do_something(item)

до:

for i, item in enumerate(my_items):
  if i == 0:
    continue
  do_something(item)


1

more_itertoolsПроект поширюється itertools.isliceобробляти негативні індекси.

Приклад

import more_itertools as mit

iterable = 'ABCDEFGH'
list(mit.islice_extended(iterable, 1, -1))
# Out: ['B', 'C', 'D', 'E', 'F', 'G']

Тому ви можете елегантно нанести на нього елементи скибочки між першими та останніми елементами перегляду:

for car in mit.islice_extended(cars, 1, -1):
    # do something

0

Я роблю це так, навіть незважаючи на те, що він працює, кожен раз:

ls_of_things = ['apple', 'car', 'truck', 'bike', 'banana']
first = 0
last = len(ls_of_things)
for items in ls_of_things:
    if first == 0
        first = first + 1
        pass
    elif first == last - 1:
        break
    else:
        do_stuff
        first = first + 1
        pass
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.