リストのすべての要素が条件に一致するかどうかを確認するにはどうすればよいですか?


208

20000のようなリストで構成されるリストがあります。各リストの3番目の要素をフラグとして使用します。少なくとも1つの要素のフラグが0である限り、このリストでいくつかの操作を実行したいのですが、次のようになります。

my_list = [["a", "b", 0], ["c", "d", 0], ["e", "f", 0], .....]

最初はすべてのフラグが0です。whileループを使用して、少なくとも1つの要素のフラグが0かどうかを確認します。

def check(list_):
    for item in list_:
        if item[2] == 0:
            return True
    return False

check(my_list)返された場合はTrue、リストの作業を続けます。

while check(my_list):
    for item in my_list:
        if condition:
            item[2] = 1
        else:
            do_sth()

実際、繰り返し処理を行っているときにmy_listの要素を削除したかったのですが、繰り返し処理を行っているため、アイテムを削除することはできません。

元のmy_listにはフラグがありませんでした:

my_list = [["a", "b"], ["c", "d"], ["e", "f"], .....]

繰り返し処理中に要素を削除できなかったため、これらのフラグを考案しました。しかし、にmy_listは多くのアイテムが含まれており、whileループは各forループでそれらすべてを読み取り、多くの時間を消費します。何か提案はありますか?


3
データ構造は問題にとって理想的ではないようです。コンテキストをもう少し説明すると、もっと適切なものを提案できるでしょう。
uselpa

おそらく、アイテムを削除する代わりに、リストを繰り返し処理するNoneか、アイテムを置き換えることができ[]ます。'check() `でリスト全体をチェックして、内部ループの各パスの前にすべてのアイテムを繰り返し処理することは、非常に遅いアプローチです。
martineau

回答:


402

ここでの最良の答えall()は、この状況に組み込まれているを使用することです。これをジェネレータ式と組み合わせて、クリーンで効率的な結果を生成します。例えば:

>>> items = [[1, 2, 0], [1, 2, 0], [1, 2, 0]]
>>> all(flag == 0 for (_, _, flag) in items)
True
>>> items = [[1, 2, 0], [1, 2, 1], [1, 2, 0]]
>>> all(flag == 0 for (_, _, flag) in items)
False

これall(flag == 0 for (_, _, flag) in items)はと直接同等であることに注意してくださいall(item[2] == 0 for item in items)。この場合は、少し読みやすくなります。

そして、フィルターの例では、リスト内包表記(もちろん、必要に応じてジェネレーター式を使用できます):

>>> [x for x in items if x[2] == 0]
[[1, 2, 0], [1, 2, 0]]

少なくとも1つの要素が0であることを確認する場合any()は、より読みやすいオプションを使用することをお勧めします。

>>> any(flag == 0 for (_, _, flag) in items)
True

ラムダ、Pythonのすべての使用に関する私の欠点は、Haskell etのような最初の引数として関数を受け入れません。その他、私も答えをリスト内包表記に変更しました。:)
Hampus Nilsson

3
@HampusNilssonリスト内包表記は、ジェネレータ式とは異なります。短絡としてall()any()たとえば、私の最初の値がと評価されたFalse場合、all()失敗し、それ以上の値をチェックせず、を返しFalseます。最初に比較のリスト全体を生成することを除いて、あなたの例は同じことをします。
Gareth Latty、2012年

14

リストのいずれかの項目が条件に違反しているかどうかを確認する場合は、次のように使用しますall

if all([x[2] == 0 for x in lista]):
    # Will run if all elements in the list has x[2] = 0 (use not to invert if necessary)

一致しないすべての要素を削除するには、次を使用します filter

# Will remove all elements where x[2] is 0
listb = filter(lambda x: x[2] != 0, listb)

2
リストの代わりにジェネレータを作成できるため[...]、in を削除all(...)できます。これにより、2つの文字が節約されるだけでなく、メモリと時間も節約されます。ジェネレーターを使用すると、一度に1つのアイテムのみが計算され(以前の結果は使用されなくなったため削除されます)、それらのいずれかが判明したFalse場合、ジェネレーターは残りの計算を停止します。
InQβ

7

このようにitertoolsのtakewhileを使用できます。ステートメントが失敗する条件が満たされると停止します。反対の方法はdropwhileになります

for x in itertools.takewhile(lambda x: x[2] == 0, list)
    print x

0

使用する別の方法itertools.ifilter。これは真実性とプロセスをチェックします(を使用lambda

サンプル-

for x in itertools.ifilter(lambda x: x[2] == 0, my_list):
    print x

0

この方法は、以下を使用するよりも少し柔軟ですall()

my_list = [[1, 2, 0], [1, 2, 0], [1, 2, 0]]
all_zeros = False if False in [x[2] == 0 for x in my_list] else True
any_zeros = True if True in [x[2] == 0 for x in my_list] else False

またはもっと簡潔に:

all_zeros = not False in [x[2] == 0 for x in my_list]
any_zeros = 0 in [x[2] for x in my_list]

単に言っall_zeros = False in [x[2] == 0 for x in my_list]たり0 in [x[2] for x in my_list]、それに応じて対応したりできませんany_zerosか?を超える顕著な改善は見られませんall()
Tripleee

いいえ、あなたのバージョン-はにall_zeros = False in [x[2] == 0 for x in my_list]評価されますがFalse、私のものはに評価されTrueます。あなたがそれをall_zeros = not (False in [x[2] == 0 for x in my_list])次に変えるならば、それは私のものと同等です。そして0 in [x[2] for x in my_list]、明らかにのためだけに働くつもりですany_zeros。しかし、私はあなたのアイデアの簡潔さが好きなので、私は私の答えを更新します
mulllhausen
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.