Reputation: 1252
I have a list of namedtuples. I would like to generate a list of a specific named element of a subset of the namedtuples in the list, based on a list of indices to select.
Example would be:
from collections import namedtuple
from operator import itemgetter
NameTuple = namedtuple("NameTuple", ['first_name', 'last_name'])
name1=NameTuple(first_name='John',last_name="Doe")
name2=NameTuple(first_name="Jane",last_name="Doe")
name3=NameTuple(first_name="Jason",last_name="Smith")
namelist=[name1,name2,name3]
While itemgetter and a list comprehension works when selecting 2 items:
inds1 = [0,1]
sublist = list(itemgetter(*inds1)(namelist))
[item.first_name for item in sublist]
Similar code using an index list of 1 fails:
inds2=[0]
sublist = list(itemgetter(*inds2)(namelist))
[item.first_name for item in sublist]
which throws an Attribute error. This is happening because sublist in this case has flattened the elements of NameTuple into a list, rather than returning a list of 1 NameTuple.
So how to avoid this flattening? I would like to have code that takes a generalized list or even None (meaning all elements) properly.
Upvotes: 0
Views: 1082
Reputation: 77857
Look at your problem iteration clause:
... for item in namelist[0]
This is not iterating through a subset of the namedtuples; it iterates through the field of namelist[0]
, which is another reference to name1
. This iteration iterates item
through name1.firstname
and name1.lastname
. THose are strings, not objects with a firstname
field.
Yes, you can iterate through a subset of your list, but that is not what you used. Perhaps you would want a specific sublist, such as
... for item in [namelist[0]]
This is a list of one element, which does have the required field.
Solution to emended problem
Extract your items more directly, instead of going through itemgetter
-- use the given subscripts:
# While itemgetter and a list comprehension works when selecting 2 items:
inds1 = [0,1]
print( [namelist[idx].first_name for idx in inds1] )
# Similar code using an index list of 1 fails:
inds2=[0]
print( [namelist[idx].first_name for idx in inds2] )
Output:
['John', 'Jane']
['John']
This works even with an empty list of indices.
Upvotes: 1