2012-03-05 3 views
36

たとえば、番号412が見つかった場合など、条件に基づいてリスト内包を解除できますか?改行リストの理解

コード:

numbers = [951, 402, 984, 651, 360, 69, 408, 319, 601, 485, 980, 507, 725, 547, 544, 
      615, 83, 165, 141, 501, 263, 617, 865, 575, 219, 390, 984, 592, 236, 105, 942, 941, 
      386, 462, 47, 418, 907, 344, 236, 375, 823, 566, 597, 978, 328, 615, 953, 345, 399, 
      162, 758, 219, 918, 237, 412, 566, 826, 248, 866, 950, 626, 949, 687, 217, 815, 67, 
      104, 58, 512, 24, 892, 894, 767, 553, 81, 379, 843, 831, 445, 742, 717, 958, 609, 842, 
      451, 688, 753, 854, 685, 93, 857, 440, 380, 126, 721, 328, 753, 470, 743, 527] 

even = [n for n in numbers if 0 == n % 2] 

ので、機能的には、それはあなたがこれを行うことになっている推測することができるもののようになります。

even = [n for n in numbers if 0 == n % 2 and break if n == 412] 

私は本当にが好む

  • 1を - ライナー
  • 何itertoolsのような他の派手なライブラリない、「純粋のpython」可能な場合は(読み:ソリューションは、あらゆるimport文または同様のを使用しないでください)
+13

「itertools」は純粋なpythonです。 – Marcin

+1

両方の条件を同時に満たすことはできません。 –

+4

... 'itertools'はPythonです...全体的に、これは普通の' for'ループの仕事のようです。 –

答えて

7
even = [n for n in numbers[:None if 412 not in numbers else numbers.index(412)] if not n % 2] 

ちょうど上記F.J.のコードを取り、412がリストにあるかどうかをチェックするために三元を追加しました。まだ1ライナーで、412がリストにない場合でも動作します。

+1

412が 'numbers'にない場合、最後の要素は偶数の場合は失われます。 – WolframH

+0

@WolframH fixed –

+0

F.J.は誰ですか?また、上記のコードはどこですか?スタックオーバーフローを(従来の)*フォーラム*で間違えてはいけません。 [ツアー]ごとに、回答は上に上がるか下に下がる可能性があります。 – usr2564301

9

412は間違いなくあなたがこれを使用することができ、リストになります場合は、次の

even = [n for n in numbers[:numbers.index(412)] if not n % 2] 

結果に412を含める場合は、そのスライスにnumbers[:numbers.index(412)+1]を使用してください。

スライスのため、これはitertoolsまたはforループソリューションより効率的ではありません(少なくともメモリ単位で)。

+0

スライスのためだけでなく、効率が悪いだけでなく、リストに対して線形検索を行う必要もあります。 –

+2

@FelixKling - それにもかかわらず、他の回答との迅速なタイムテストでは、提供されるサンプルデータの方が速いことがわかります。私は間違いなくデータセットが増えるにつれて他の人たちにそれを渡すと期待しています。 –

+3

@FelixKling:412の線形検索は超高速のCコードですが、他のソリューションではPythonコードで412がテストされ、いくつかのソリューションはすべての数値*に対してCPythonで高価な関数を呼び出します。私はこのソリューションがより速いと確信しています! - リストコピーも非常に高速なCコードで行われます。メモリが不足している場合を除き、パフォーマンスの問題は発生しません。 (最初の数字が412で、リストに10 ** 6のエントリがある場合は問題ありませんが、412が最後の数字であれば、この解決方法はまだ非常に速いはずです) – WolframH

33

あなたはitertools.takewhile()と一緒にジェネレータ式を使用することができます。

even_numbers = (n for n in numbers if not n % 2) 
list(itertools.takewhile(lambda x: x != 412, even_numbers)) 

編集:私はただのimport Sを使用しない要件に気づきました。まあ、私はとにかくこの答えをここに残す。

+3

これは正しい答えです。 – Marcin

+5

もし彼が本当に彼のライナーを一つにしたいのであれば、 "[n for itertools.takewhile(lambda x:x!= 412、numbers)n '2でない場合は' –

38

はそれをキャッチするためにStopIterationlistを高めるための機能を使用します。それはワンライナーではありません文句方のため

>>> def end_of_loop(): 
...  raise StopIteration 
... 
>>> even = list(end_of_loop() if n == 412 else n for n in numbers if 0 == n % 2) 
>>> print(even) 
[402, 984, 360, 408, 980, 544, 390, 984, 592, 236, 942, 386, 462, 418, 344, 236, 566, 978, 328, 162, 758, 918] 

:それを文句方のため

even = list(next(iter(())) if n == 412 else n for n in numbers if 0 == n % 2) 

はハックであるといけませんプロダクションコードで使用される:まあ、あなたは正しい。 間違いなく。 (リストの内包表記を含む)のリストが表示用

+0

これはリスト理解ではなく、私の理解からですが、それは1ライナーです(関数は、それらの 'raise'文のためのpython)、それは何か欠点を持っていないようです。 + 1ed – Flavius

+2

面白いトリック!とにかく私はそれを実際のコードで使っていますが、とにかく素晴らしい見解です。 –

+0

+0。賢いしかし、ハッキーではなく、1つのライナー。 –

0

構文はここにある:http://docs.python.org/reference/expressions.html#list-displays

あなたが見ることができるように、特別なwhileまたはuntil構文はありません。あなたが得ることができる最も近いです:

even_numbers = (n for n in numbers if 0 == n % 2) 
list(itertools.takewhile(lambda x: x != 412, even_numbers)) 

(スヴェンMarnachの答えから取られたコード、私はこれを入力している間に掲載します)。

+0

Downvoter:なぜですか? – Marcin

+3

私はdownvoteをしませんでしたが、あなたが他の誰かからコードを取得したためだと思います。少なくともあなたはそれを認めました。私はそれをupvoteよ。 – CoffeeRain

2

私はOPがlist-comprehensionbreakを使用する方法について尋ねたと私も似たような探していた、私は今後の参考のためにここに私の調査結果を投稿するだろうと思ったがあるため、これは非常に古いポストである知っています。

breakを調査している間、私は「休憩」反復一度呼び出し可能function値がsentinel値に等しいというイテレータを返すiter(callable, sentinel)としてiterの間でほとんど知られていない機能が来ました。

>>> help(iter) 
Help on built-in function iter in module __builtin__: 

iter(...) 
    iter(collection) -> iterator 
    iter(callable, sentinel) -> iterator 

    Get an iterator from an object. In the first form, the argument must 
    supply its own iterator, or be a sequence. 
    In the second form, the callable is called until it returns the sentinel. 

ここで難しい部分は、与えられた問題に適合する関数を定義しています。この場合、まずlistnumbersを、lambda関数に外部変数として入力するx = iter(numbers)を使用してiteratorに変換する必要があります。

次に、私たちの呼び出し可能な関数は、次の値を吐き出すためのイテレータへの呼び出しです。イテレータは、次に、我々のセンチネル値(この場合は412)と比較され、その値に達すると "中断"します。

print [i for i in iter(lambda x=iter(numbers): next(x),412) if i %2 == 0] 

>>> 
[402, 984, 360, 408, 980, 544, 390, 984, 592, 236, 942, 386, 462, 418, 
344, 236, 566, 978, 328, 162, 758, 918]