demathieu
demathieu

Reputation: 479

Check if item is member of list of objects

I'm looking for a clean way to check if an item is member of a list of objects. Basically this is what I want to do:

class Constant:
    def __init__(self,name,value):
        self.name = name
        self.value = value

list = [Constant('el1',1),Constant('el2',2)]
list2= ['el4','el5','el1']

for item in list2:
    #clean solution for this if clause is needed (I'm aware list.name triggers an error)
    if item in list.name:
        print 'it is a member'

So it is important to me that the item matches only on the name, the value has no meaning when searching. I know I can solve this by adding an additional for loop like this:

for item in list2:
  for itemConstant in list:
    if item == itemConstant.name:
        print 'it is a member'

But I want to be sure there is no better solution than this.

Upvotes: 1

Views: 1562

Answers (3)

Padraic Cunningham
Padraic Cunningham

Reputation: 180391

Since the value has no meaning use a set with in as strings are hashable and you will have a 0(1) lookups, storing the names from the instances in a set:

st = {Constant('el1',1).name,Constant('el2',2).name}
lst2  = ['el4','el5','el1']

for c in lst2:
   if c in st:
       print('it is a member')

Or make lst2 a set:

lst = [Constant('el1',1), Constant('el2',2)]
st  = {'el4','el5','el1'}

for c in lst:
   if c.name in st:
       print(c.name)

I presume you want exact matches as "foo" in "foobar" would be True.

You can also leave the original list as is an create a set from the instance names:

lst = [Constant('el1', 1), Constant('el2', 2)]

lst2 = ['el4', 'el5', 'el1']
st = {c.name for c in lst}
for c in lst2:
    if c in st:
        print('it is a member')

So you still have an 0(n) solution as it just requires one more pass over your instances lst.

Upvotes: 1

Martijn Pieters
Martijn Pieters

Reputation: 1121386

Make list2 a set and loop over your list of constants to test each against that set. Use the any() callable to exit early when a match is found:

constants = [Constant('el1', 1), Constant('el2',2)]
elements = {'el4', 'el5', 'el1'}

if any(c.name in elements for c in constants):
    print 'is a member'

This reduces the problem to one loop; membership testing against a set is a O(1) constant time operation on average. The loop is exited early when a match is found, further reducing the number of tests made.

Upvotes: 0

Daniel
Daniel

Reputation: 42748

You can use any:

for item in list2:
    if any(item == c.name for c in list):
        print 'it is a member'

Upvotes: 4

Related Questions