Coder Perfect

Find an item in the list with an attribute equal to a certain value (that meets any condition)

Problem

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 is the most effective method of locating 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 don’t believe that utilizing generators and reduce() will make a difference because we’ll still be iterating through a list.

ps. : This is only an example of an equation to value. Of course, we want an element that can be used in every situation.

Asked by seler

Solution #1

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

This retrieves the first item from the list that matches the condition, or None if none do. It’s the single-expression form I favor.

However,

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

The naive loop-break version is delightfully Pythonic: it’s short, sweet, and to-the-point. To make it mirror the one-behavior: liner’s

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.

Answered by agf

Solution #2

It was just included for the sake of completeness because it had not been discussed previously. The good ol’ filter to filter your elements to be filtered.

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’m aware that list comprehensions are favored in Python, or at least that’s what I’ve read, but to be honest, I don’t see the problem. Of course, Python is not a functional programming language, but Map, Reduce, and Filter are the most common use cases in functional programming.

So there you have it. Know what you’re doing when it comes to 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

Answered by Nima Mousavi

Solution #3

Consider the following scenario: The following is the array we have.

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

Now we need to locate the object in the array with an id of 1.

next(x for x in li if x["id"] == 1 )
[x for x in li if x["id"] == 1 ][0]
def find(arr , id):
    for x in arr:
        if x["id"] == id:
            return x
find(li , 1)

‘id’: 1, ‘name’: ‘ronaldo’ is the output of all the previous procedures.

Answered by Mohammad Nazari

Solution #4

This is an old question, but I use it pretty often (for version 3.8). It’s a little syntactic salt, but it beats the top answer in that you can get a list of results (if there are any) by eliminating the [0], and it still defaults to None if nothing is found. Simply change the x.value==value to whatever you’re looking for in any other condition.

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

Answered by Colin Hicks

Solution #5

You may also utilize the __eq__ function in your Test class to provide rich comparison and use the in operator. I’m not sure if this is the best method on its own, but it might be beneficial if you need to compare Test instances based on value somewhere else.

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"

Answered by tm-

Post is based on https://stackoverflow.com/questions/7125467/find-object-in-list-that-has-attribute-equal-to-some-value-that-meets-any-condi