Reputation: 110143
I have the following list of tuples:
items = [
('john jones', ['Director', 'Screenwriter', 'Producer']),
('eric smith', ['Screenwriter']),
('anne smith', ['Producer']),
('emily smith', ['Director']),
('steven jones', ['Director', 'Screenwriter'])
]
I need to sort it such that "Director" appears before "Screenwriter" appears before "Producer". The actual ordering therein doesn't matter. For example, this would be a valid outcome:
items = [
('john jones', ['Director', 'Screenwriter', 'Producer']),
('emily smith', ['Director']),
('steven jones', ['Director', 'Screenwriter'])
('anne smith', ['Producer']),
('eric smith', ['Screenwriter']),
]
Is there a way to do this sort doing sorted(items, key=lambda x: ?)
, or do I have to iterate each item in the list?
Upvotes: 0
Views: 213
Reputation: 64563
Of course, there is a way:
$ cat sort.py
order = ['Director', 'Screenwriter', 'Producer']
items = [
('john jones', ['Director', 'Screenwriter', 'Producer']),
('eric smith', ['Screenwriter']),
('anne smith', ['Producer']),
('emily smith', ['Director']),
('steven jones', ['Director', 'Screenwriter'])
]
for i in sorted(items, key = lambda x: order.index(x[1][0])):
print i
Let's try it:
$ python sort.py
('john jones', ['Director', 'Screenwriter', 'Producer'])
('emily smith', ['Director'])
('steven jones', ['Director', 'Screenwriter'])
('eric smith', ['Screenwriter'])
('anne smith', ['Producer'])
And when you want to sort equal eintries by name, you just need a tuple (Lattyware 's idea):
for i in sorted(items, key = lambda x: (order.index(x[1][0]), x[0])):
print i
Upvotes: 3
Reputation: 88977
Here is what I consider the best overall solution, mainly a mashup of other answers here:
import collections
items = collections.OrderedDict([
('john jones', ['Director', 'Screenwriter', 'Producer']),
('emily smith', ['Director']),
('steven jones', ['Director', 'Screenwriter']),
('anne smith', ['Producer']),
('eric smith', ['Screenwriter']),
])
ordering = {'Director': 1, 'Screenwriter': 2, 'Producer': 3}
def order(item):
name, values = item
return ordering.get(values[0], float("inf")), name
print(sorted(items.items(), key=order))
Giving us:
[('emily smith', ['Director']), ('john jones', ['Director', 'Screenwriter', 'Producer']), ('steven jones', ['Director', 'Screenwriter']), ('eric smith', ['Screenwriter']), ('anne smith', ['Producer'])]
And roles not in the ordering
dict will be placed at the end. They will be first sorted by role, then by name.
This presumes the sublists are pre-sorted. If not, it is easy to sort them first.
Upvotes: 0