Reputation: 3501
I have a list of named tuples:
from collections import namedtuple
T = namedtuple('T', ['attr1', 'attr2', 'attr3', 'attr4'])
t1 = T('T1', 1, '1234', 'XYZ')
t2 = T('T2', 2, '1254', 'ABC')
t3 = T('T2', 2, '1264', 'DEF')
l = [t1, t2, t3]
I want to check if an element exists in the list T
where attr1 = 'T2'
.
Checking if the list contains such an element by doing:
any(x for x in l if x.attr1 == 'T2')
only returns the information whether such a namedtuple is in the list or not.
I would like to also pop this namedtuple from the list.
One way of doing it is:
if any(x for x in l if x.attr1 == 'T2'):
result = [x for x in l if x.attr1 == 'T2'].pop()
However, I don't like this solution, since I'm looping over the list l
twice.
Is there any better/more-elegant way of doing this?
Upvotes: 7
Views: 5076
Reputation: 102
If it is allowed to get the result as an array:
result = filter(lambda x: x.attr1 == 'T2', l)
Or if you just want to get one then:
result = filter(lambda x: x.attr1 == 'T2', l).pop()
Upvotes: 1
Reputation: 214967
Or you can use next
:
try:
result = next(t for t in l if t.attr1 == 'T2')
except StopIteration:
result = None
result
# T(attr1='T2', attr2=2, attr3='1254', attr4='ABC')
Upvotes: 1
Reputation: 78554
If you need one item and don't necessarily want to pop, you can use next
with your existing generator expression:
result = next(x for x in l if x.attr1 == 'T2')
Upvotes: 2
Reputation: 402553
How about an old-school for loop? Simple, elegant, and you loop only once.
for x in l:
if x.attr1 == 'T2':
break
result = x
Upvotes: 3