Python'daki loop için ilk giriş atlansın mı?


187

Python, Nasıl gibi bir şey yapabilirim:

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

4
Ben bir acemiyim, ama kullanıyorum for n, i in enumerate(cars): if n!= 0: do something to i. mantık, daha sonra hedefleyebileceğiniz her değere bir 'sayaç' eklemesidir if n == some_value. bu örnekte, ilki dışında i'nin her örneğine bir şeyler yapar.
user1063287

Yanıtlar:


268

Diğer cevaplar sadece bir dizi için geçerlidir.

Herhangi bir yinelenebilir için, ilk öğeyi atlamak için:

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

Sonuncuyu atlamak istiyorsanız şunları yapabilirsiniz:

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
Ayrıca bkz Sven Marnach 'ın cevabı
agf

2
Cars.pop (0) ve cars.pop () yapmanın iyi çalıştığını gördüm.
dreamwork801

@ dreamwork801 Cevabım ve ilk yorumda bağladığım Sven'ler, yineleme başlamadan önce veriler üzerinde O (n) işlemi gerektirmedikleri için yinelenebilir, hatta sonsuz olanlar için çalışıyorlar. Önerin ve Abhjit'in ikisi de sadece diziler için çalışıyor, yinelenemez.
agf

356

Python'daki ilk öğeyi atlamak için

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

veya son elem atlamak için

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

Bu konsepti herhangi bir sekans için kullanabilirsiniz.


52
Tüm tekrarlanabilirler için değil, tüm diziler için .
Sven Marnach

2
Bellek kullanımına ne dersiniz? Dilim alt dizinin yeni bir kopyasını oluşturur mu?
Voyager

@Voyager Evet, Yeni kopya yapıyor.
Srinivas Reddy Thatiparthy

27

İlk kalemleri atlamanın en iyi yolu:

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

bu durumda islice, yineleyicinin sonunu gösteren 1 başlangıç ​​noktası ve None son noktası ile çağrılır.

Bir yinelenebilir öğenin sonundan öğeleri atlayabilmek için, uzunluğunu bilmeniz gerekir (bir liste için her zaman mümkündür, ancak yineleyebileceğiniz her şey için zorunlu değildir). örneğin, islice (arabalar, 1, len (arabalar) -1), otomobil listesindeki ilk ve son öğeleri atlar.


Sven'in (değersiz) cevabına bir göz atın. isliceUzunluğunu bilmeden veya bir kerede kesinlikle gerekli olandan daha fazla öğe depolamaksızın, yinelenebilir herhangi bir öğenin başında ve / veya sonunda rastgele sayıda öğenin atlanmasını kapsar .
agf

Sven'in cevabı aslında tüm yineleyiciyi bellekte saklayacak - collections.deque yineleyici üzerinden çalışacaktır. Collections.deque (xrange (10000000)) gibi bir şey yapmayı deneyin. İlk öğeyi atlamak istiyorsanız tüm
girişleri belleğe kaydetmeye gerek yok

2
Bir islice, dequetüm yineleyiciye değil , iletilen öğedir ve sonunda atlanacak öğe sayısının uzunluğudur. Tüm yineleyiciyi belleğe kaydetmez.
agf

26

İşte bir yinelenebilir başlangıcından ve sonundan istediğiniz sayıda öğeyi atlayan daha genel bir jeneratör işlevi:

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()

Örnek kullanım:

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

İçin hızlı bir yol eklemek isteyebilir at_end == 0.
agf

collections.deque (...) hemen yineleyiciden geçecektir. Bu, atlama (xrange (10000000), 1), gerçekten olmamasına rağmen çok fazla bellek kaplayacağı anlamına gelir.
Roee Shenberg

4
@RoeeShenberg: skip(xrange(10000000), 1)kullanacak at_end=0, bu yüzden sadece sıfır elemanını tüketecek parametre deque()olacak . Bu çok fazla bellek kaplamaz. islice(it, 0)it
Sven Marnach

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

3
listDeğişken adı olarak kullanmayın
Abhijit

OP sadece ilk elemanı atlamak istiyor. neden: -1?
luke14free

6
Aslında ayrılmış değil ; ad listyeniden bağlanabilir. Eğer bu yüzden olmamalı yerine edemez , onu kullanın.
jscs

@ luke14free, soru ilk öğeyi atla diyor, ancak kod yorumu gerçekten ilk ve son atlamak istediğini ima ediyor.
JerseyMike

@ luke14free başlığın söylediği şey, kodun içine yazdığı şey değil: "ilk veya son ise atla"
KurzedMetal

4

Misal:

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

Python indeksinde 0'dan başlar, yinelemede manipülasyonlar yapmak için dilimleme operatörünü kullanabiliriz.

for i in range(1,-1):

3

@SvenMarnach kullanıcısının Yanıtına dayanarak, biraz daha basit ve deque kullanmadan

>>> 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]

Ayrıca Not, benim timeitsonucuma göre, bu deque çözümden biraz daha hızlı

>>> 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

Kullanarak tee(), hala jeneratör için belleğin bir listesini oluşturuyorsunuz, değil mi? (senin it1)
Jabberwockey

2

Sözdiziminiz aslında Python değil.

Python'daki yinelemeler, sözdizimi ile kapların içeriğidir (teknik olarak yineleyiciler üzerindedir) for item in container. Bu durumda, kap carslistedir, ancak ilk ve son öğeleri atlamak istiyorsunuz, yani cars[1:-1](python listeleri sıfır tabanlı, negatif sayılar sondan sayılıyor ve :sözdizimini dilimliyor.

Yani istiyorsun

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

4
Bu, yalnızca bir sekansla yinelenebilir (örneğin bir jeneratör) ile çalışmaz.
Roee Shenberg

2

Alternatif bir yöntem:

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

İşte tercih ettiğim seçim. Döngüye fazla bir şey eklemeyi gerektirmez ve yerleşik araçlardan başka bir şey kullanmaz.

Git:

for item in my_items:
  do_something(item)

için:

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


1

more_itertoolsProje uzanır itertools.isliceolumsuz endekslerini işlemek için.

Misal

import more_itertools as mit

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

Bu nedenle, dilim öğelerini bir yinelenebilir öğenin ilk ve son öğeleri arasında zarif bir şekilde uygulayabilirsiniz:

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

0

Her seferinde bir kesmek gibi görünse de böyle yapıyorum:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.