在列表中查找属性等于某个值(满足任何条件)的对象

时间:2011-08-19 17:52:26

标签: python django list

我有对象列表。我想在这个列表中找到一个(第一个或任何)对象,它具有等于value的属性(或方法结果 - 无论如何)。

找到它的最佳方式是什么?

这是测试用例:

  class Test:
      def __init__(self, value):
          self.value = value

  import random

  value = 5

  test_list = [Test(random.randint(0,100)) for x in range(1000)]

  # that I would do in Pascal, I don't believe isn't anywhere near 'Pythonic'
  for x in test_list:
      if x.value == value:
          print "i found it!"
          break

我认为使用生成器和reduce()不会有任何区别,因为它仍然会遍历列表。

ps。:value的方程只是一个例子。当然,我们希望获得满足任何条件的元素。

8 个答案:

答案 0 :(得分:316)

next((x for x in test_list if x.value == value), None)

这将从列表中获取与条件匹配的第一个项目,如果没有项目匹配则返回None。这是我首选的单表达形式。<​​/ p>

然而,

for x in test_list:
    if x.value == value:
        print "i found it!"
        break

天真的循环中断版本,完全是Pythonic - 它简洁,清晰,高效。使其与单行的行为相匹配:

for x in test_list:
    if x.value == value:
        print "i found it!"
        break
else:
    x = None

如果您没有None退出循环,这会将x分配给break

答案 1 :(得分:18)

一个简单的示例: 我们有以下数组

li = [{"id":1,"name":"ronaldo"},{"id":2,"name":"messi"}]

现在,我们要在数组中找到ID等于1的对象

  1. 结合列表理解使用方法next
next(x for x in li if x["id"] == 1 )
  1. 使用列表理解并返回第一项
[x for x in li if x["id"] == 1 ][0]
  1. 自定义功能
def find(arr , id):
    for x in arr:
        if x["id"] == id:
            return x
find(li , 1)

以上所有方法的输出为{'id': 1, 'name': 'ronaldo'}

答案 2 :(得分:14)

由于尚未提及完成。 好的过滤器可过滤您的过滤元素。

功能编程ftw。

rfind

我知道通常在python列表中理解是首选或至少是 这就是我读到的内容,但我不认为这个问题是诚实的。当然,Python不是FP语言,但Map / Reduce / Filter是完全可读的,是函数式编程中最标准的标准用例。

所以你去吧。了解你的功能编程。

过滤条件列表

它不会比这更容易:

####### Set Up #######
class X:

    def __init__(self, val):
        self.val = val

elem = 5

my_unfiltered_list = [X(1), X(2), X(3), X(4), X(5), X(5), X(6)]

####### Set Up #######

### Filter one liner ### filter(lambda x: condition(x), some_list)
my_filter_iter = filter(lambda x: x.val == elem, my_unfiltered_list)
### Returns a flippin' iterator at least in Python 3.5 and that's what I'm on

print(next(my_filter_iter).val)
print(next(my_filter_iter).val)
print(next(my_filter_iter).val)

### [1, 2, 3, 4, 5, 5, 6] Will Return: ###
# 5
# 5
# Traceback (most recent call last):
#   File "C:\Users\mousavin\workspace\Scripts\test.py", line 22, in <module>
#     print(next(my_filter_iter).value)
# StopIteration


# You can do that None stuff or whatever at this point, if you don't like exceptions.

答案 3 :(得分:1)

我遇到了类似的问题,并针对列表中没有任何对象符合要求的情况设计了一个小优化。(对于我的用例,这导致了主要的性能提升):

除了列表test_list之外,我还有一个额外的set test_value_set,它包含我需要过滤的列表值。所以这里agf的解决方案的其他部分变得非常快。

答案 4 :(得分:0)

您还可以通过Test类的__eq__方法实现丰富的比较,并使用in运算符。 不确定这是否是最好的独立方法,但是如果您需要在其他地方比较基于Test的{​​{1}}实例,则可能会有用。

value

答案 5 :(得分:0)

对于以下代码,xGen是一个匿名生成器表达式,yFilt是一个过滤器对象。请注意,对于xGen,将在列表用尽时返回附加的None参数,而不是抛出StopIteration。

arr =((10,0), (11,1), (12,2), (13,2), (14,3))

value = 2
xGen = (x for x in arr if x[1] == value)
yFilt = filter(lambda x: x[1] == value, arr)
print(type(xGen))
print(type(yFilt))

for i in range(1,4):
    print('xGen: pass=',i,' result=',next(xGen,None))
    print('yFilt: pass=',i,' result=',next(yFilt))

输出:

<class 'generator'>
<class 'filter'>
xGen: pass= 1  result= (12, 2)
yFilt: pass= 1  result= (12, 2)
xGen: pass= 2  result= (13, 2)
yFilt: pass= 2  result= (13, 2)
xGen: pass= 3  result= None
Traceback (most recent call last):
  File "test.py", line 12, in <module>
    print('yFilt: pass=',i,' result=',next(yFilt))
StopIteration

答案 6 :(得分:0)

旧问题,但我经常使用(对于3.8版)。它有点语法,但是它比顶部的答案更具优势,因为您只需删除[0]就可以检索结果列表(如果有多个结果),并且它仍默认为None如果什么也没找到。对于其他任何情况,只需将x.value==value更改为所需的内容即可。

_[0] if (_:=[x for x in test_list if x.value==value]) else None

答案 7 :(得分:-1)

您可以这样做

dict = [{
   "id": 1,
   "name": "Doom Hammer"
 },
 {
    "id": 2,
    "name": "Rings ov Saturn"
 }
]

for x in dict:
  if x["id"] == 2:
    print(x["name"])

这就是我用来在长对象数组中查找对象的原因。