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

我有对象列表。我想在此列表中找到一个属性(或方法结果-任意)等于的(第一个或任何对象)对象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()不会有任何区别,因为它仍然会遍历list。

ps .:方程式to value只是一个例子。当然我们要获得满足任何条件的元素。

I’ve got list of objects. I want to find one (first or whatever) object in this list that has attribute (or method result – whatever) equal to value.

What’s is the best way to find it?

Here’s test case:

  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 it's anywhere near 'Pythonic'
  for x in test_list:
      if x.value == value:
          print "i found it!"
          break
  

I think using generators and reduce() won’t make any difference because it still would be iterating through list.

ps.: Equation to value is just an example. Of course we want to get element which meets any condition.


回答 0

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

这将从列表中获得与条件匹配的第一项,None如果没有匹配项,则返回。这是我首选的单表达式形式。

然而,

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给。xbreak

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

This gets the first item from the list that matches the condition, and returns None if no item matches. It’s my preferred single-expression form.

However,

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

The naive loop-break version, is perfectly Pythonic — it’s concise, clear, and efficient. To make it match the behavior of the one-liner:

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

This will assign None to x if you don’t break out of the loop.


回答 1

由于尚未提及仅仅是为了完成。好的ol’过滤器可过滤您要过滤的元素。

函数编程

####### 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.

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

所以你去了。了解您的函数式编程。

过滤条件列表

没有比这更容易的了:

next(filter(lambda x: x.val == value,  my_unfiltered_list)) # Optionally: next(..., None) or some other default value to prevent Exceptions

Since it has not been mentioned just for completion. The good ol’ filter to filter your to be filtered elements.

Functional programming ftw.

####### 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.

I know that generally in python list comprehensions are preferred or at least that is what I read, but I don’t see the issue to be honest. Of course Python is not an FP language, but Map / Reduce / Filter are perfectly readable and are the most standard of standard use cases in functional programming.

So there you go. Know thy functional programming.

filter condition list

It won’t get any easier than this:

next(filter(lambda x: x.val == value,  my_unfiltered_list)) # Optionally: next(..., None) or some other default value to prevent Exceptions

回答 2

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

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'}

A simple example: We have the following array

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

Now, we want to find the object in the array that has id equal to 1

  1. Use method next with list comprehension
next(x for x in li if x["id"] == 1 )
  1. Use list comprehension and return first item
[x for x in li if x["id"] == 1 ][0]
  1. Custom Function
def find(arr , id):
    for x in arr:
        if x["id"] == id:
            return x
find(li , 1)

Output all the above methods is {'id': 1, 'name': 'ronaldo'}


回答 3

我遇到了一个类似的问题,针对列表中没有对象符合要求的情况设计了一个小型优化(对于我的用例,这导致了重大的性能改进):

与列表test_list一起,我还有一个额外的集合test_value_set,它由我需要过滤的列表的值组成。因此,这里的agf解决方案的其他部分变得非常快。

I just ran into a similar problem and devised a small optimization for the case where no object in the list meets the requirement.(for my use-case this resulted in major performance improvement):

Along with the list test_list, I keep an additional set test_value_set which consists of values of the list that I need to filter on. So here the else part of agf’s solution becomes very-fast.


回答 4

你可以做这样的事情

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

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

那就是我用来在长对象数组中查找对象的东西。

You could do something like this

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

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

Thats what i use to find the objects in a long array of objects.


回答 5

您还可以通过方法为Test类和use in运算符实现丰富的比较。不知道这是否是最好的独立方法,但是如果您需要Test基于value其他地方比较实例,这可能会很有用。

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

    def __eq__(self, other):
        """To implement 'in' operator"""
        # Comparing with int (assuming "value" is int)
        if isinstance(other, int):
            return self.value == other
        # Comparing with another Test object
        elif isinstance(other, Test):
            return self.value == other.value

import random

value = 5

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

if value in test_list:
    print "i found it"

You could also implement rich comparison via method for your Test class and use in operator. Not sure if this is the best stand-alone way, but in case if you need to compare Test instances based on value somewhere else, this could be useful.

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

    def __eq__(self, other):
        """To implement 'in' operator"""
        # Comparing with int (assuming "value" is int)
        if isinstance(other, int):
            return self.value == other
        # Comparing with another Test object
        elif isinstance(other, Test):
            return self.value == other.value

import random

value = 5

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

if value in test_list:
    print "i found it"

回答 6

对于下面的代码,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

For below code, xGen is an anonomous generator expression, yFilt is a filter object. Note that for xGen the additional None parameter is returned rather than throwing StopIteration when the list is exhausted.

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))

Output:

<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

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。