【问题标题】:Searching a list of objects in Python在 Python 中搜索对象列表
【发布时间】:2009-02-28 18:06:20
【问题描述】:

假设我正在创建一个类似于 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 或其他内容。而且这个例子可能过于简单了。

标签: python


【解决方案1】:

您可以通过列表推导获得所有个匹配元素的列表:

[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

【讨论】:

  • 或者,any(custom_filter(x) for x in myList if x.n == 30) 这只是您作为内置函数的“包含”函数。
  • nosklo 上的语法错误——在生成器周围需要额外的一组 ()。
  • 最好将此答案与 gahooa 的 (stackoverflow.com/a/598602/2349267) 合并。
【解决方案2】:

简单、优雅、功能强大:

与内置函数结合的生成器表达式... (python 2.5+)

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

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

任何(可迭代) -> 如果可迭代的任何元素为真,则返回真。相当于:

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

【讨论】:

  • 不错。仅供参考,您可以执行任何操作(x for x in mylist if x.n == 10)来保存一些括号(也 == not =)。
  • 我更喜欢使用any(x for x in mylist if x['n'] == 10),但这是个好主意
  • 非常经典的解决方案。也提高了 imo 的可读性。
【解决方案3】:

为了完整起见,我们不要忘记可能工作的最简单的事情:

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

【讨论】:

    【解决方案4】:
    [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
    

    【讨论】:

    • 这是一个很好的答案,因为“第一”方法可能是最常见的用例。
    • 太好了,谢谢!匹配索引是我正在寻找的。是否有快捷方式可以使用它直接索引列表以访问另一个字段?现在我得到一个列表条目列表(只有一个条目,所以它是一个包含一个项目的列表)。要获取索引,我需要先执行 result[0],然后才能使用它来索引列表。从问题示例中,我想从特定的 n 访问 n_squared:myList[index of myList.n==5].n_squared
    【解决方案5】:
    filter(lambda x: x.n == 5, myList)
    

    【讨论】:

    • 对于想要学习 Python 的人来说,了解 lambda 是基础。
    • 嗯,是的,也不是——使用列表推导和排序关键函数,比如 operator.attrgetter,我几乎从不使用lambdas。
    • 我喜欢简单?
    【解决方案6】:

    您可以使用in 在集合中查找项目,并使用列表推导来提取您感兴趣的字段。这(适用于列表、集合、元组以及任何定义__contains__ 或@ 987654325@)。

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

    另见:

    【讨论】:

      【解决方案7】:

      您应该在您的Data 类中添加__eq__ 和__hash__ 方法,它可以检查__dict__ 属性是否相等(相同的属性),然后它们的值是否也相等。

      如果你这样做了,你可以使用

      test = Data()
      test.n = 5
      
      found = test in myList
      

      in 关键字检查 test 是否在 myList 中。

      如果您只想在 Data 中使用 n 属性,您可以使用:

      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
      

      【讨论】:

        【解决方案8】:

        考虑使用字典:

        myDict = {}
        
        for i in range(20):
            myDict[i] = i * i
        
        print(5 in myDict)
        

        【讨论】:

        • 或者:d = dict((i, i*i) for i in range(20))
        • 它解决了我用来说明问题的琐碎问题,但并没有真正解决我的根本问题。我一直在寻找的答案(5 年前)是列表理解。 :)
        【解决方案9】:

        另一种方法是使用 next() 函数。

        matched_obj = next(x for x in list if x.n == 10)
        

        【讨论】:

          【解决方案10】:

          将以下列表推导与index 方法结合使用:

          data_n = 30
          j = [data.n for data in mylist].index(data_n)
          print(mylist[j].data.n == data_n)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-01-14
            • 2011-07-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-10-12
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多