Pythonのforループの最初のエントリをスキップしますか?


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の各インスタンスに対して何かを行います。
user1063287 2013年

回答:


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'


2
cars.pop(0)とcars.pop()がうまくいくことがわかりました。
dreamwork801

@ dreamwork801最初のコメントでリンクする私の回答とSvenは、反復が始まる前にデータに対するO(n)演算を必要としないため、無限の反復でも機能します。あなたの提案とAbhjitの提案はどちらもシーケンスに対してのみ機能し、反復可能ではありません。
-agf

356

Pythonの最初の要素をスキップするには、次のように書くだけです。

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

または最後のelemをスキップする

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

この概念はどのシーケンスにも使用できます。


52
すべての反復可能オブジェクトではなく、すべてのシーケンスです。
Sven Marnach

2
メモリ使用量はどうですか?スライスはサブシーケンスの新しいコピーを作成しますか?
Voyager

@Voyagerはい、新しいコピーを作成します。
Srinivas Reddy Thatiparthy

27

最初のアイテムをスキップする最良の方法は次のとおりです。

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

この場合のisliceは、開始点が1、終了点がNoneで呼び出され、イテレーターの終了を示します。

イテラブルの最後から項目をスキップできるようにするには、その長さを知る必要があります(リストでは常に可能ですが、反復できるすべてのものである必要はありません)。たとえば、islice(cars、1、len(cars)-1)は、carsリストの最初と最後の項目をスキップします。


Svenの(あまり評価されていない)回答を見てください。彼はislice、長さがわからなかったり、絶対に必要な以上のアイテムを一度にメモリに保存したりせずに、イテラブルの最初と最後で任意の数のアイテムをスキップする方法について説明しています。
agf

スヴェンの答えは実際にはイテレータ全体をメモリに格納します-collections.dequeはイテレータを実行します。collections.deque(xrange(10000000))のようなことを試してください。最初の項目をスキップする場合、すべてのintをメモリに保存する必要はありません...
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

collections.deque(...)はすぐにイテレータを通過します。つまり、skip(xrange(10000000)、1)は、実際には必要ではありませんが、大量のメモリを消費します。
Roee Shenberg

4
@RoeeShenberg:skip(xrange(10000000), 1)はを使用するat_end=0ので、toのパラメーターdeque()はでありislice(it, 0)、これはのゼロ要素しか消費しませんit。これは多くのメモリを消費しません。
Sven Marnach

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

3
list変数名として使用しない
Abhijit

OPは最初の要素のみをスキップしたい。なぜ:-1?
luke14free 2012

6
実際には予約されていません。名前listは再バインドできます。あなたが理由ですべきではない、というよりはできません、それを使用しています。
jscs 2012

@ luke14free、質問は最初の要素をスキップすることを言いますが、彼のコードコメントは彼が本当に最初と最後をスキップしたいことを意味します。
JerseyMike 2012

@ 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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.