より大きなリストのn番目ごとのアイテムのリストを返すPythonの方法


170

0から1000までの数字のリストがあるとし[0, 10, 20, 30, ... ]ましょう。最初とすべての後続の10番目のアイテムのリストを生成するpythonic / efficient方法はありますか?

はい、forループを使用してこれを行うことができますが、これを行うためのきちんとした方法があるかどうか、おそらく1行でも疑問に思っていますか?

回答:


289
>>> lst = list(range(165))
>>> lst[0::10]
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160]

これは、ループして各要素の係数をチェックするよりも約100倍速いことに注意してください。

$ python -m timeit -s "lst = list(range(1000))" "lst1 = [x for x in lst if x % 10 == 0]"
1000 loops, best of 3: 525 usec per loop
$ python -m timeit -s "lst = list(range(1000))" "lst1 = lst[0::10]"
100000 loops, best of 3: 4.02 usec per loop

4
確かに、リスト内包表記は一般により強力です。OTOH、質問は既存のリストを提示し、その場合、スライスはうまく機能します。
ネッドデイリー

私は以下のリストの理解の答えでこれについてコメントしました。「if x%10 == 0 "の場合は注意してください。これはこの特定のリストの例でのみ機能しますが、たとえば入力リストがl = range(0,1000,2)の場合、10番目ごとにプルアウトされません。
Andre Miller

12
@Andre:とてもそうです。したがって、これは謙虚な言語機能の例であるスライス演算子であり、この場合(1)で正しい結果を簡単に取得できるようになります。(2)結果はより簡潔になります。(3)たまたま2桁速い。(1)は、これまでのところ最も重要な懸念事項ですが、言語を注意深く設計および実装したおかげで、3つすべてが1の価格で手に入ります。素晴らしい質問と回答です。
Ned Deily、2009

2
0冗長ですl[0::10]l[::10]読みやすく、混乱が少なくなります。
Konstantin Schubert

リストの理解については0.5秒、リストのスライスについては0.4秒のパフォーマンス比較に驚いています。非常に遅いようですが、リストのスライスには、サイズが1000のリストに対して10万のループが必要なのはなぜですか?
Damo

57
  1. source_list[::10] が最も明白ですが、これはイテラブルでは機能せず、大きなリストではメモリ効率が良くありません。
  2. itertools.islice(source_sequence, 0, None, 10) イテラブルで機能し、メモリ効率が良いですが、大きなリストと大きなステップに対するおそらく最速のソリューションではありません。
  3. (source_list[i] for i in xrange(0, len(source_list), 10))

1
+1ベストアンサー、IMO。3つの提案すべてが一般的なソリューションです(つまり、与えられたソースリストを使用します)。ジェネレーターソリューション(3.)は、ソースリストのインデックスでフィルターをかけるので便利です。それはおそらく2と同じくらいメモリ効率が良いです。インデックスと結果リストはどちらもジェネレータであり、したがって遅延して構築されます。これは、結果リストを単一のチャンクで必要としない場合はおそらく最速です。ジェネレータのlen()がないため、ソースリストがジェネレータである場合にのみ、Paulの "item、i in enumerate(l)"イディオムを使用します。ところで、どのイテラブルは1.では動作しませんか?発電機?!
ThomasH

Iterable = __iter __()メソッドを持つオブジェクト、イテレータを返す(next()メソッドを持つオブジェクト)
Denis Otkidach


19

マニュアルから: s[i:j:k] slice of s from i to j with step k

li = range(100)
sub = li[0::10]

>>> sub
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]

13
newlist = oldlist[::10]

これにより、リストの10番目ごとの要素が選択されます。


4

範囲関数のステップパラメーターを使用して取得しないのはなぜですか?

l = range(0, 1000, 10)

比較のために、私のマシンでは:

H:\>python -m timeit -s "l = range(1000)" "l1 = [x for x in l if x % 10 == 0]"
10000 loops, best of 3: 90.8 usec per loop
H:\>python -m timeit -s "l = range(1000)" "l1 = l[0::10]"
1000000 loops, best of 3: 0.861 usec per loop
H:\>python -m timeit -s "l = range(0, 1000, 10)"
100000000 loops, best of 3: 0.0172 usec per loop

3
@SilentGhost:それは本当ですが、これは初心者の質問なので、範囲関数は彼らが本当にやりたいことかもしれないので、それは有効な答えだと思います。(上限は1000ではなく1001にする必要があります)
スコットグリフィス

2
existing_list = range(0, 1001)
filtered_list = [i for i in existing_list if i % 10 == 0]

1
range(0、1001、10)がすでに10番目ごとの要素しかとらないときにif句があるのはなぜですか?
Autoplectic 2009

4
ここで同じコメント、これは「より大きなリストのn番目ごとのアイテムのリストを返すPythonの方法」というより一般的な問題を解決しません。解決策は、サンプルリストの値が0〜1000であり、アイテムのみをプルするという事実に依存します10個ごとのアイテムではなく、10で割り切れる値を持つリストから。
Andre Miller、

1
まあ、OPは書きます:「我々は0から1000までの数字のリストがあります」。したがって、彼には一般的な解決策の必要はありません。

1
彼は「Say we have ..」と書いており、これはほんの一例です。0から1000のリストから10番目ごとの数値が本当に必要な場合、答えはrange(0,1001,10)または類似したものになります。
Andre Miller

1

これは、メンバーシップテストの一部としてリストの内容を使用しない、「10番目ごとの項目」リスト内包のより良い実装です。

>>> l = range(165)
>>> [ item for i,item in enumerate(l) if i%10==0 ]
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160]
>>> l = list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
>>> [ item for i,item in enumerate(l) if i%10==0 ]
['A', 'K', 'U']

しかし、これは単にリストのスライスを使用するよりもはるかに遅いです。


-9

リスト内包表記は、まさにそのために作られています。

smaller_list = [x for x in range(100001) if x % 10 == 0]

これらの詳細については、Pythonの公式ドキュメントをご覧ください。http//docs.python.org/tutorial/datastructures.html#list-comprehensions


上限は10000ではなく1000にする必要があります。範囲は999で停止するため、ソリューションには上限1000は含まれません。list-comprehensionへのリンクの+1。

19
これは実際には10番目のアイテムごとにプルするのではなく、10で割り切れる値を持つすべてのアイテムをプルします。この特定の例では同じですが、そうではない場合があります。
Andre Miller
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.