【问题标题】:Searching within a list of Objects in Python在 Python 中的对象列表中搜索
【发布时间】:2012-03-01 06:14:21
【问题描述】:

让我们假设以下对象:

class Test:
    id1 = ""
    id2 = ""
    id3 = ""

    def __init__(self,arg1,arg2,arg3):
        self.id1 = arg1
        self.id2 = arg2
        self.id3 = arg3

可以看出,这个类必须包含 3 个唯一的 id。

t = []
t.append(Test(200,201,193))
t.append(Test(403,221,213))
t.append(Test(3,523,2003))

假设上面的代码,我在列表 t 中找到 id1 = 403、id2 = 221 和 id3 =213 的对象的最简单方法是什么?

提前致谢。

【问题讨论】:

  • 你需要为t保留一个特定的顺序,或者你可以排序吗?您会在t 中反复查找实例吗?
  • 我应该在问题中说明,是的,列表 t 可以排序。另外,是的,例如,我会在 t 内反复查找。
  • 这些是什么类型的对象?如果您已经知道要查找的东西的 id1、id2 和 id3,为什么还需要实际对象(即还有什么)?您真的想将几种 ID 与底层对象相关联吗? IE。 ID 值是数据的基本部分,还是您用来查找它们的内容?
  • 请注意,id1 = "" 之类的行没有必要也没有帮助。
  • 在新的 Python 2 代码中,最好总是继承 object 而不是什么都没有,这会让你使用“新式类”。这样做有很多好处,但在您以后需要它们之前,您不必考虑太多。

标签: python


【解决方案1】:

在比较中使用迭代。

matches = [i for i in t if i.id1 == id1 and i.id2 == id2 and i.id3 == id3]

如果你知道它在那里并且只有一个,你可以这样做:

match = next(i for i in t if i.id1 == id1 and i.id2 == id2 and i.id3 == id3)

但请注意,如果没有这样的项目,这将引发StopIteration。不过next 可以采用默认值,因此如果您不确定它是否存在,您可以指定一个默认值:

match = next((i for i in t if i.id1 == id1 and i.id2 == id2 and i.id3 == id3), None)

【讨论】:

  • 很好 -- 但请注意 next 采用可选的默认值 -- 如果您传递一个,则不会引发 StopIteration 异常。
  • @senderle:好点;我忘记了这一点。现在已集成到答案中。
  • i.id1 == id1 and i.id2 == id2 and i.id3 == id3 的替代代码样式是 (i.id1, i.id2, i.id3) == (id1, id2, id3)。根据值的含义,您可能会发现这更具可读性。
【解决方案2】:

如果您有很多对象并且您需要多次查找匹配项,那么首先将它们预处理到具有(id1,id2,id3) 键的字典中可能会更有效。这样你就可以在 O(1) 中找到对象。

构建字典:

# In Python 2.7+
the_dict = {(o.id1, o.id2, o.id3) : o for o in objects}
# In Python 2.6-
the_dict = dict((o.id1, o.id2, o.id3),o) for o in objects)

然后在O(1)中找到对象:

the_dict[(id1,id2,id3)]

请注意,将对象作为字典值放置不会复制它们(Python 从不隐式复制),因此您不必太担心内存影响。

【讨论】:

    【解决方案3】:
    >>> [x for x in t if x.id1==200 and x.id2==201 and x.id3==193]
    [<__main__.Test object at 0x00BA3030>]
    

    【讨论】:

      【解决方案4】:

      如果您需要将对象存储在列表中(即,如果您不能使用 dict 并完全避免搜索),我会在 Test 中添加一个方法将 ID 作为元组返回:

      class Test(object):
          ...
          def getids(self):
              return (self.id1, self.id2, self.id3)
      

      然后您可以简单地循环并检查您的 id 元组来搜索:

      for obj in t:
          if obj.getids() == (403, 221, 213):
              return obj
      

      这就像清理界面一样“简单”。为了加快速度,您应该使用字典而不是列表,并且您可以一步检索对象:

      t = dict()  
      obj = Test(403, 221, 213)
      t[obj.getids()] = obj      # Store in dictionary, using ID as the key
      

      然后您可以按 ID 检索对象,或检查它们是否存在于 t 中,采用以下任一方式:

      found = t[(403, 221, 213)]       # returns object or raises KeyError
      found = t.get((403, 221, 213))   # returns object or returns None
      if (403, 221, 213) in t:         # True or False
      

      【讨论】:

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