1

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.

1
  • I can't change the type of item collections I'm using due to restrictions of other key components of the project. Commented Jun 7, 2015 at 15:03

3 Answers 3

4

You can use any:

for item in list2: if any(item == c.name for c in list): print 'it is a member' 
Sign up to request clarification or add additional context in comments.

Comments

1

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.

4 Comments

OP didn't say that list2 has distinct elements, though.
@ZiyaoWei, then store a set of Constant('el1',1).name's
Problem is that if I want to use sets I need to convert my lists to sets and convert them back, I need lists to communicate with other parts.
@demathieu, you don't, you can create a set just for lookups as per the last part of the answer, if you have a large amount of data you will see the cost of building the set will be offset by the efficient lookups, it will be the difference between O(n) and 0(n^2)
0

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.

2 Comments

Problem is that if I want to use sets I need to convert my lists to sets and convert them back, I need lists to communicate with other parts.
@demathieu: you can easily convert a set back to a list (just use list(setobject). And are you certain that other parts just need something they can loop over rather than a list?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.