Pythonイテレータから最後のアイテムを取得する最もクリーンな方法


110

Python 2.6のイテレータから最後のアイテムを取得する最良の方法は何ですか?たとえば、

my_iter = iter(range(5))

取得する最短コード/クリーンな方法は何ですか 4からではmy_iter

私はこれを行うことができましたが、それは非常に効率的ではないようです:

[x for x in my_iter][-1]

4
イテレータは、要素を繰り返し処理し、最後の要素にはアクセスしないことを想定しています。単にrange(5)[-1]を使用できない理由は何ですか?
フランク

7
@フランク-実際のイテレータは、iter(range(5))
クリス・ルッツ

3
@フランク:イテレータを提供するのは、実際にははるかに複雑なジェネレータ関数であるという事実。私はこの例を単純にして何が起こっているのかを明確にするために作りました。
Peter

4
イテレータの最後の項目が必要な場合は、何か間違っている可能性が高いです。しかし、答えは、イテレータを反復するより明確な方法は実際にはないということです。これは、イテレータにサイズがなく、実際には決して終了しない可能性があるため、最後のアイテムがない可能性があるためです。(もちろん、コードが永久に実行されることを意味します)。したがって、長引く質問は次のとおりです。なぜイテレータの最後の項目が必要なのですか。
Lennart Regebro、2010年

3
@ピーター:質問を更新してください。所有している質問には、たくさんのコメントを追加しないでください。質問を更新してコメントを削除してください。
S.Lott、

回答:


100
item = defaultvalue
for item in my_iter:
    pass

4
なぜプレースホルダー「デフォルト値」なのですか?なんでNone?これがまさにNone目的です。一部の機能固有のデフォルト値が正しい可能性があることを示唆していますか?イテレータが実際に反復しない場合は、アウトオブバンド値は、より多くのいくつかの誤解を招くような機能固有のデフォルトより有意義。
S.Lott、

46
defaultvalueは、私の例の単なるプレースホルダーです。Noneデフォルト値として使用する場合は、それを選択します。どれもが常に最も賢明なデフォルトであるとは限らず、帯域外になることさえありません。個人的には、 'defaultvalue = object()'を使用して、それが本当に一意の値であることを確認する傾向があります。デフォルトの選択はこの例の範囲外であることを示しています。
Thomas Wouters

28
@ S.Lott:空のイテレータとNoneそれが最終値として持つイテレータの違いを区別することはおそらく有用です
John La Rooy

8
すべての組み込みコンテナタイプのすべてのイテレータにデザインエラーがありますか?初めて聞いたのは:)
Thomas Wouters '26

7
これはおそらくより速い解決策ですが、forループでリークする変数に依存しています(一部の機能、他のバグ-恐らくFPの人は恐ろしいです)。とにかく、Guidoはこれが常にこのように機能するので、安全に使用できると述べました。
tokland

68

dequeサイズ1のa を使用します。

from collections import deque

#aa is an interator
aa = iter('apple')

dd = deque(aa, maxlen=1)
last_element = dd.pop()

6
これは実際には、長いシーケンスを使い果たす最も速い方法ですが、forループよりもわずかに高速です。
Sven Marnach、2011年

11
技術的に正しいことを+1しますが、読者は、「これを本当に最適化する必要がありますか?」、「これはそれほど明確ではない、Pythonicではありません」、「より速い速度は実装に依存します。変わるかもしれません。」
leewz 2014

1
また、それは思い出に
残ります

6
@EelcoHoogendoorn maxlenが1であっても、なぜメモリホグなのですか?
クリスウェッセリング

1
これまでに紹介したすべてのソリューションから、これが最も高速でメモリ効率の高いソリューションであることがわかりました。
Markus Strauss、

66

Python 3.xを使用している場合:

*_, last = iterator # for a better understanding check PEP 448
print(last)

Python 2.7を使用している場合:

last = next(iterator)
for last in iterator:
    continue
print last


サイドノート:

通常、上記のソリューションは通常のケースで必要なものですが、大量のデータを処理する場合はdeque、サイズ1 を使用する方が効率的です。(ソース

from collections import deque

#aa is an interator
aa = iter('apple')

dd = deque(aa, maxlen=1)
last_element = dd.pop()

1
@virtualxtc:下線は単なる識別子です。手前の星は「リストを拡大する」と言っています。より読みやすいでしょう*lst, last = some_iterable
pepr

4
@virtualxtc nope _はpythonの特別な変数であり、最後の値を保存するため、または値を気にしないのでクリーンアップするために使用されます。
DhiaTN

1
そのPython 3ソリューションはメモリ効率が良くありません。
Markus Strauss

3
@DhiaTNはい、あなたは絶対的に正しいです。実際、私はあなたがたくさん示したPython 3イディオムが好きです。「ビッグデータ」では機能しないことを明確にしたかっただけです。そのためにcollections.dequeを使用しますが、これはたまたま高速でメモリ効率が良いです(martin23487234のソリューションを参照)。
Markus Strauss

1
このpy3.5 +の例はPEP 448にあるはずです。素晴らしい。
EliadL 2019年

33

__reversed__利用可能であればおそらく使用する価値があります

if hasattr(my_iter,'__reversed__'):
    last = next(reversed(my_iter))
else:
    for last in my_iter:
        pass

27

単純な:

max(enumerate(the_iter))[1]

8
ああ、これは賢いです。最も効率的または読みやすいわけではありませんが、賢いです。
timgeb

6
だから大声で考えてください...これenumerateは次の(index, value)ように返されるため機能します(0, val0), (1, val1), (2, val2)... ...そして、デフォルトmaxではタプルのリストが与えられると、2つの最初の値が等しくない限り、タプルの最初の値のみと比較します。インデックスを表すからです。次に、末尾の添え字は、maxが(idx、value)タプル全体を返すのに対して、にのみ関心があるためvalueです。面白いアイデア。
テイラーエドミストン2017年

21

これはラムダのために空のforループよりも速くなる可能性は低いですが、おそらく他の誰かにアイデアを与えるでしょう

reduce(lambda x,y:y,my_iter)

iterが空の場合、TypeErrorが発生します


私見、これは概念的に最も直接的です。代わりに、引き上げのTypeError空の反復可能なため、あなたはまたの初期値を経由して、デフォルト値を供給することができreduce()、例えば、last = lambda iterable, default=None: reduce(lambda _, x: x, iterable, default)
egnha

9

これがあります

list( the_iter )[-1]

反復の長さが本当に壮大な場合、つまりリストを具体化するとメモリが使い果たされる場合は、設計を再考する必要があります。


1
これは最も簡単な解決策です。
laike9m 2014年

2
タプルを使用するのがやや良い。
クリストファー・スミス

9
最後の文に強く同意しません。リストの代わりにイテレータを使用する主な理由は、非常に大きなデータセット(一度に読み込まれるとメモリの制限を超える可能性がある)で作業することです。
ポール

@Paul:一部の関数は反復子のみを返します。これは、その場合に実行するための短くて読みやすい方法です(非叙事詩リストの場合)。
serv-inc

これは、悪い悪い悪い習慣として避けるべき最も効率の悪い方法です。もう1つは、sort(sequence)[-1]を使用してシーケンスの最大要素を取得することです。ソフトウェアエンジニアになりたい場合は、これらの病気のパターンを使用しないでください。
Maksym Ganenko

5

私は使うだろう reversedますが、イテレータの代わりにシーケンスのみを取る、かなり恣意的です。

どのような方法でも、イテレータ全体を実行する必要があります。最大の効率で、イテレータが二度と必要ない場合は、すべての値を破棄することができます。

for last in my_iter:
    pass
# last is now the last item

しかし、これは次善のソリューションだと思います。


4
reverse()はイテレータをとらず、ただシーケンスをとります。
Thomas Wouters、2010年

3
それはまったく恣意的ではありません。イテレータを逆にする唯一の方法は、すべてのアイテムをメモリに保持しながら、最後まで反復することです。私、e、あなたはそれを元に戻す前に、まずそれからシーケンスを作る必要があります。もちろん、これはそもそもイテレータの目的に反するものであり、明確な理由もなく突然大量のメモリを使い果たすことになります。つまり、実際には恣意的なものの反対です。:)
Lennart Regebro 2010年

@Lennart-私が恣意的に言ったとき、私は迷惑なことを意味しました。午前中の数時間後には、私は自分の論文に私の言語スキルを集中させています。
Chris Lutz

3
けっこうだ。IMOですが、イテレータを受け入れた場合はほとんど不快になります。これは、ほとんどすべての使用が悪いアイデア(tm)になるためです。:)
Lennart Regebro 2010年

3

バーチャルツールのライブラリには、素敵なソリューションを提供します。

from toolz.itertoolz import last
last(values)

ただし、コア以外の依存関係を追加しても、この場合のみ使用する価値はありません。



0

私は使うだけです next(reversed(myiter))


8
TypeError:reverse()への引数はシーケンスでなければなりません
Labo

0

質問はイテレータの最後の要素を取得することですが、イテレータがシーケンスに条件を適用することによって作成された場合、reversedを使用して、逆のシーケンスの「最初の」を見つけることができます。シーケンス自体の逆。

不自然な例

>>> seq = list(range(10))
>>> last_even = next(_ for _ in reversed(seq) if _ % 2 == 0)
>>> last_even
8

0

または、無限イテレータの場合は次のように使用できます。

from itertools import islice 
last = list(islice(iterator(), 1000))[-1] # where 1000 is number of samples 

私はそれが遅くなるだろうと思ったがdeque、それは同じくらい速く、実際にはforループメソッドよりも速い(どういうわけか)


-6

質問は間違っており、複雑で非効率的な回答しか導きません。イテレータを取得するには、もちろん、反復可能なものから始めます。これにより、ほとんどの場合、最後の要素にアクセスするためのより直接的な方法が提供されます。

iterableからiteratorを作成すると、それがiterableが提供する唯一のものであるため、要素の処理に行き詰まります。

したがって、最も効率的で明確な方法は、最初にイテレータを作成するのではなく、イテラブルのネイティブアクセスメソッドを使用することです。


5
では、どのようにしてファイルの最後の行を取得しますか?
Brice M. Dempsey 2015

@ BriceM.Dempsey最善の方法は、ファイル全体(おそらく巨大)を反復処理するのではなく、ファイルサイズから100を引いて、最後の100バイトを読み取り、改行をスキャンします(ない場合)。シナリオによっては、ステップバックサイズを増やすこともできます。膨大な数の行を読むことは、明らかに最適なソリューションではありません。
Alfe
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.