Pythonでオブジェクトのリストを検索する


90

データ要素を保持するために、Cスタイルの構造体と同様に機能する単純なクラスを作成しているとしましょう。特定の値に等しい属性を持つオブジェクトのオブジェクトのリストを検索する方法を理解しようとしています。以下は、私が何をしようとしているのかを説明する簡単な例です。

例えば:

class Data:
    pass

myList = []

for i in range(20):
    data = Data()
    data.n = i
    data.n_squared = i * i
    myList.append(data)

myListリストを検索して、n == 5の要素が含まれているかどうかを確認するにはどうすればよいですか?

私はPythonドキュメントをグーグル検索して検索してきましたが、これをリスト内包表記で実行できると思うかもしれませんが、よくわかりません。ちなみに、Python 2.4.3を使用する必要があるため、新しいgee-whiz 2.6または3.xの機能は利用できません。


おそらくあなたの例の意図しない癖:myList = [Data()。n == 0、Data()。n = 1、...]ここで、data.nはrange()によって割り当てられ、data.nはmyListへのインデックス。したがって、インデックス値でmyListを参照するだけで、任意のData()インスタンスをプルアップできます。もちろん、後でmyList [0] .n = 5.2などを変更することもできます。そして、例はおそらく過度に単純化されました。
DevPlayer

回答:


130

リスト内包表記を使用して、一致するすべての要素のリストを取得できます。

[x for x in myList if x.n == 30]  # list of all elements with .n==30

リストに一致する要素が含まれているどうかを判断し、それを(比較的)効率的に行う場合は、次のようにすることができます。

def contains(list, filter):
    for x in list:
        if filter(x):
            return True
    return False

if contains(myList, lambda x: x.n == 3)  # True if any element has .n==3
    # do stuff

25
または、ビルトインとしての「contains」関数であるany(myListのxの場合はcustom_filter(x)for myList if xn == 30)。
nosklo 2009

noskloの構文エラー-ジェネレーターの周りに()の追加セットが必要です。
gahooa 2009

そうではありません。試してみてください。
Robert Rossney、2009年

1
この回答をgahooa(stackoverflow.com/a/598602/2349267)とマージするとよいでしょう。
Roman Hwang

76

シンプル、エレガント、パワフル:

ビルトインと組み合わせたジェネレータ式…(python 2.5+)

any(x for x in mylist if x.n == 10)

any()次のように定義されているPython 組み込みを使用します。

any(iterable)イテラブルの -> いずれかの要素がtrueの場合、trueを返します。に相当:

def any(iterable):
    for element in iterable:
        if element:
            return True
    return False

いいね。FYIあなたはいくつかの括弧を節約するために(また、==ではない=)、mylistのx for x x = = 10)を行うことができます。
Jacob Gabrielson、

any(x for x in mylist if x['n'] == 10)は使用を好みますが、良いアイデアです
Alex Montoya

46

完全を期すために、おそらく機能する最も単純なものを忘れないでください。

for i in list:
  if i.n == 5:
     # do something with it
     print "YAY! Found one!"

38
[x for x in myList if x.n == 30]               # list of all matches
[x.n_squared for x in myList if x.n == 30]     # property of matches
any(x.n == 30 for x in myList)                 # if there is any matches
[i for i,x in enumerate(myList) if x.n == 30]  # indices of all matches

def first(iterable, default=None):
  for item in iterable:
    return item
  return default

first(x for x in myList if x.n == 30)          # the first match, if any

1
おそらく最も一般的なユースケースである「最初の」方法のため、これは良い答えです。
ギャランティ2013年

まことにありがとうございます!マッチインデックスは私が探していたものでした。これを使用してリストに直接インデックスを付け、別のフィールドにアクセスするショートカットはありますか?これで、リストエントリのリストが表示されます(エントリは1つしかないので、項目が1つのリストです)。インデックスを取得するには、それを使用してリストのインデックスを作成する前に、result [0]を実行する必要があります。質問の例から、特定のnからn_squaredにアクセスしたいとします。myList [myList.n == 5のインデックス] .n_squared
Frieke

31
filter(lambda x: x.n == 5, myList)

25
Pythonを学びたい人にとっては、ラムダを理解することが基本です。
vartec 2009年

2
ええ、はい、いいえ-リストの内包表記と、operator.attrgetterのような主要な関数の並べ替えの作成者と一緒に、私はほとんどlambdasを使用しません。
Ben Hoyt

9

を使用inして、コレクション内のアイテムを検索し、リスト内包表記を使用して、目的のフィールドを抽出できます。これは、リスト、セット、タプル、__contains__またはを定義するものすべてで機能します__getitem__

if 5 in [data.n for data in myList]:
    print "Found it"

以下も参照してください。


4

クラスにメソッド__eq____hash__メソッドを追加する必要があります。Data__dict__属性が等しい(同じプロパティ)かどうか、そしてそれらの値も等しい。

あなたがそれをしたなら、あなたは使うことができます

test = Data()
test.n = 5

found = test in myList

in場合は、キーワードをチェックしtestていますmyList

nプロパティのみをData使用する場合は、次のように使用できます。

class Data(object):
    __slots__ = ['n']
    def __init__(self, n):
        self.n = n
    def __eq__(self, other):
        if not isinstance(other, Data):
            return False
        if self.n != other.n:
            return False
        return True
    def __hash__(self):
        return self.n

    myList = [ Data(1), Data(2), Data(3) ]
    Data(2) in myList  #==> True
    Data(5) in myList  #==> False

3

辞書の使用を検討してください:

myDict = {}

for i in range(20):
    myDict[i] = i * i

print(5 in myDict)

または:d = dict((i、i * i)for i for range(20))
hughdbrown

これは、質問の説明に使用した些細な問題を解決しますが、根本的な質問は実際には解決しませんでした。私が探していた答え(5年以上前)はリストの理解でした。:)
m0j0 2014

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.