在Python中搜索对象列表


89

假设我正在创建一个简单的类以类似于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

Answers:


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
或者,仅是“包含”作为内置函数的任何(如果xn == 30,则myList中x的custom_filter(x))。
nosklo

nosklo上的语法错误-生成器周围需要额外的()集。
gahooa

不是这样 试试看。
罗伯特·罗斯尼

1
最好将这个答案与gahooa的(stackoverflow.com/a/598602/2349267)合并在一起。
Roman Hwang

75

简单,优雅,功能强大:

生成器表达式与内置表达式联合使用(python 2.5+)

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

使用Python any()内置函数,其定义如下:

any(iterable) -> 如果iterable中的任何元素为true,则返回True。相当于:

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

真好 仅供参考,您可以执行任何操作(如果xn == 10,则在mylist中x为x)以保存一些括号(也==不是=)。
雅各布·加布里埃尔森

我更喜欢使用,any(x for x in mylist if x['n'] == 10)但是个好主意
亚历克斯·蒙托亚

45

仅出于完整性考虑,我们不要忘记可能可行的最简单方法:

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年

十分感谢!比赛索引就是我想要的。是否有捷径可用来直接索引列表以访问另一个字段?现在,我得到一个列表条目的列表(只有一个条目,因此它是一个包含一项的列表)。要获取索引,我需要执行result [0]才能使用它为列表建立索引。从问题示例中,我想从特定的n访问n_squared:myList [myList.n == 5的索引] .n_squared
Frieke

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

25
对于想学习Python的人来说,了解lambda是基础。
vartec

2
是的,不是,通过列表理解和排序像operator.attrgetter这样的关键函数,我几乎从未使用过lambdas。
Ben Hoyt 2012年

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关键字检查是否testmyList

如果您只想拥有一个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 range in(20))
hughdbrown

它解决了我以前用来说明问题的琐碎问题,但并没有真正解决我的根本问题。我一直在寻找答案(5年前)是列表理解。:)
m0j0

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.