Pythonで「逆」リストを作成する最良の方法は?


89

Pythonで、アイテムが他のリストのアイテムと同じであるが逆の順序である新しいリストを作成する最良の方法は何ですか?(既存のリストをそのまま変更したくありません。)

ここに私に起こった1つの解決策があります:

new_list = list(reversed(old_list))

old_list複製して、その複製を元に戻すこともできます。

new_list = list(old_list) # or `new_list = old_list[:]`
new_list.reverse()

私が見落としているより良いオプションはありますか?そうでない場合、上記のアプローチのいずれかを他のものよりも使用する説得力のある理由(効率など)はありますか?

回答:


205
newlist = oldlist[::-1]

[::-1]逆に、すなわち、-1のステップで、スライスシーケンス全体:スライシング(私の妻アンナは手段;-)「火星スマイリー」と呼ぶのが好き。すべてのシーケンスで機能します。

これ(およびあなたが言及した代替案)は「浅いコピー」と同等であることに注意してください。つまり、アイテムが変更可能であり、それらに対してミューテーターを呼び出す場合、元のリストに保持されているアイテムのミューテーションも、逆のリスト、またはその逆。これを回避する必要がある場合は、copy.deepcopy(常にコストがかかる可能性がある操作ですが)、この場合.reverseはが続く唯一の適切なオプションです。


あら!それエレガントです。数日前まで、スライスするときに「ステップ」を含めることが可能であることを知りませんでした。今、私はそれなしでどうやって手に入れたのだろうと思っています!ありがとう、アレックス。:)
davidchambers 09/10/14

1
これが浅いコピーを生成することを言及してくれてありがとう。必要なのはこれだけなので、コードに火星のスマイリーを追加します。
davidchambers 2010

13
これは実際には、元の提案よりもはるかに魔法のように見え、読みにくくなっていlist(reversed(oldlist))ます。マイナーなマイクロ最適化以外にも、好むために何らかの理由がある[::-1]にはreversed()
ブライアンキャンベル

@BrianCampbell:それの「魔法」とは何ですか?スライスについて少し理解すれば、それは完全に理にかなっています。スライシングを理解していない場合は…まあ、Pythonのキャリアのかなり早い段階で、スライシングを学ぶ必要があります。もちろん、リストを必要reversedしない場合には、メモリや無駄な時間を費やさずに済むため、非常に有利です。ただし、リスト必要な場合、[::-1]代わりにlist(reversed())を使用する[listcomp]ことは、代わりにを使用することに似ていlist(genexpr)ます。
abarnert 2014

10
@abarnert私が使用するコードでは、3番目のスライス引数がめったに表示されないので、それを使用している場合は、その意味を調べる必要があります。一度実行しても、ステップが負の場合にデフォルトの開始値と終了値が入れ替わっていることはまだ明らかではありません。一見すると、3番目の引数の意味を調べず[::-1]に、リストの最後の要素を逆にするのではなく、削除することを意味していると思います。reversed(list)それが何をしているかを正確に述べる; 「明示的は暗黙的よりも優れている」、「読みやすさを重視」、「疎は密よりも優れている」という意味で、その意図を詳しく説明しています。
ブライアンキャンベル

56

さあ、みましょうtimeitヒント:アレックス[::-1]は最速です:)

$ p -m timeit "ol = [1, 2, 3]; nl = list(reversed(ol))"
100000 loops, best of 3: 2.34 usec per loop

$ p -m timeit "ol = [1, 2, 3]; nl = list(ol); nl.reverse();"
1000000 loops, best of 3: 0.686 usec per loop

$ p -m timeit "ol = [1, 2, 3]; nl = ol[::-1];"
1000000 loops, best of 3: 0.569 usec per loop

$ p -m timeit "ol = [1, 2, 3]; nl = [i for i in reversed(ol)];"
1000000 loops, best of 3: 1.48 usec per loop


$ p -m timeit "ol = [1, 2, 3]*1000; nl = list(reversed(ol))"
10000 loops, best of 3: 44.7 usec per loop

$ p -m timeit "ol = [1, 2, 3]*1000; nl = list(ol); nl.reverse();"
10000 loops, best of 3: 27.2 usec per loop

$ p -m timeit "ol = [1, 2, 3]*1000; nl = ol[::-1];"
10000 loops, best of 3: 24.3 usec per loop

$ p -m timeit "ol = [1, 2, 3]*1000; nl = [i for i in reversed(ol)];"
10000 loops, best of 3: 155 usec per loop

更新: inspectorG4dgetによって提案されたリストcompメソッドが追加されました。結果は自分で説明します。


8
ただのメモ-これは反転コピーリストの作成には正確ですが、反転の方が反復の方が効率的です[::-1]
Tadhg McDonald-Jensen '28

7

調整

しばしば不要なlist()変換をせずに「逆転」のパフォーマンスを示す、sdolanによるtimeit計算のベースラインベンチマーク/調整を提供することは価値があります。このlist()操作は、ランタイムに26 usecsを追加します。イテレーターが受け入れられない場合にのみ必要です。

結果:

reversed(lst) -- 11.2 usecs

list(reversed(lst)) -- 37.1 usecs

lst[::-1] -- 23.6 usecs

計算:

# I ran this set of 100000 and came up with 11.2, twice:
python -m timeit "ol = [1, 2, 3]*1000; nl = reversed(ol)"
100000 loops, best of 3: 11.2 usec per loop

# This shows the overhead of list()
python -m timeit "ol = [1, 2, 3]*1000; nl = list(reversed(ol))"
10000 loops, best of 3: 37.1 usec per loop

# This is the result for reverse via -1 step slices
python -m timeit "ol = [1, 2, 3]*1000;nl = ol[::-1]"
10000 loops, best of 3: 23.6 usec per loop

結論:

これらのテストの結論はreversed()スライスよりも[::-1]12.4 usecs速い


15
reverse()は遅延評価される反復子オブジェクトを返すので、一般的にスライス表記[::-1]との公平な比較ではないと思います。
虹色に輝く2013

1
のようにイテレータを直接使用できる場合でも''.join(reversed(['1','2','3']))、sliceメソッドの方が30%以上高速です。
dansalmo 2013年

1
最初の2つのテストで同じ結果が得られたのも不思議ではありません。
MestreLion 2014

私の結果はこれによりよく似ています。ol [::-1]は、list(reversed(ol))の約2倍の時間がかかります。ol [::-1]メソッドは、書き込む文字数が少なくなります。ただし、list(reversed(ol))は初心者のPythonプログラマにとっておそらくより読みやすく、私のマシンではより高速です。
dhj
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.