DivinusVox
DivinusVox

Reputation: 1191

Python: Sorting a list using another list as an order

I'm curious if there is a way to optimize in a situation I'm facing currently.

I have a list of strings representing categories to group and order data by:

['first', 'third', 'second']

This corresponds to a list of dicts containing objects of those categories which need to be sorted according to them:

[{'color':'yellow', 'section':'third'},{'color':'red', 'section':'first'}, {'color': 'blue', 'section':'second'}]

The data list should be sorted via the order given in the first set, in this case resulting in:

[{'color':'red', 'section':'first'},{'color':'yellow', 'section':'third'},{'color': 'blue', 'section':'second'}]

My current solution:

sortedList = []
for section in orderList:
  for item in dataList:
    if item['section'] == section: sortedList.append(item)

Is there a cleaner way I can be sorting this?

Upvotes: 2

Views: 230

Answers (5)

jamylak
jamylak

Reputation: 133764

>>> dicts = [{'color':'yellow', 'section':'third'},{'color':'red', 'section':'first'}, {'color': 'blue', 'section':'second'}]
>>> L = ['first', 'third', 'second']
>>> order = dict(zip(L, range(len(L)))) # Dictionary for O(1) lookup
>>> sorted(dicts, key=lambda d: order[d['section']])
[{'color': 'red', 'section': 'first'}, {'color': 'yellow', 'section': 'third'}, {'color': 'blue', 'section': 'second'}]

This method will be O(N) instead of O(N log N) for the sort:

>>> sorted_sections = ['first', 'third', 'second']
>>> dicts = [{'color':'yellow', 'section':'third'},{'color':'red', 'section':'first'}, {'color': 'blue', 'section':'second'}]
>>> dict_by_section = {d['section']:d for d in dicts}
>>> [dict_by_section[section] for section in sorted_sections]
[{'color': 'red', 'section': 'first'}, {'color': 'yellow', 'section': 'third'}, {'color': 'blue', 'section': 'second'}]

Upvotes: 3

Wei Li
Wei Li

Reputation: 471

orderList = ['first', 'third', 'second']
dataList = [{'color':'yellow', 'section':'third'},{'color':'red', 'section':'first'}, {'color': 'blue', 'section':'second'}]

orderDict = dict((v,offset) for offset, v in enumerate(orderList))

print sorted(dataList, key=lambda d: orderDict[d['section']])

Upvotes: 0

Serdalis
Serdalis

Reputation: 10489

here is a more optimised version for you:

sort_key = lambda x: ks.index(x['section'])

print(sorted(dicts, key=sort_key))

Upvotes: 2

Volatility
Volatility

Reputation: 32308

You can use the built in sorted function.

>>> lst = ['first', 'third', 'second']
>>> dcts = [{'color':'yellow', 'section':'third'}, {'color':'red', 'section':'first'}, {'color': 'blue', 'section':'second'}]
>>> sorted(dcts, key=lambda dct: lst.index(dct['section']))
[{'section': 'first', 'color': 'red'}, {'section': 'third', 'color': 'yellow'}, {'section': 'second', 'color': 'blue'}]

Upvotes: 3

NPE
NPE

Reputation: 500923

You could just use sorted() with key:

In [6]: o = ['first', 'third', 'second']

In [7]: l = [{'color':'yellow', 'section':'third'},{'color':'red', 'section':'first'}, {'color': 'blue', 'section':'second'}]

In [8]: sorted(l, key=lambda x:o.index(x['section']))
Out[8]: 
[{'color': 'red', 'section': 'first'},
 {'color': 'yellow', 'section': 'third'},
 {'color': 'blue', 'section': 'second'}]

This does a linear search on o. If o can be large, @jamylak's solution should be preferred.

Upvotes: 2

Related Questions