Python: sort lists in dictonary of lists, where one list is a key to sorting

lets say I have a dictonary

d = {
u'a': [1, 4, 6, 7],
u'b': [9, 9, 9, 8],
u'c': ['g', 'a', 'b', '9'],
u'd': [5, 1, 10, 2],
}

I want to sort simultaneously lists inside that dictionary, where a key to sorting is an value on list d[u'd'] lets say, that result of sorting will be

new_d = {
u'a': [4, 7, 1, 6],
u'b': [9, 8, 9, 9],
u'c': ['a', '9', 'g', 'b'],
u'd': [1, 2, 5, 10] <- we have sorted by that list
}

Upvotes: 2

Views: 94

Answers (3)

Padraic Cunningham
Padraic Cunningham

Reputation: 180391

from operator import itemgetter
srt_key = [i for i, e in sorted(enumerate(d["d"]), key=itemgetter(1))]

new_d = {}

for k,v in d.items():
    new_d[k] = list(itemgetter(*srt_key)(v))

print(new_d)
{'c': ['a', '9', 'g', 'b'], 'a': [4, 7, 1, 6], 'b': [9, 8, 9, 9], 'd': [1, 2, 5, 10]}

Or using a dict comp:

new_d = {k: list(itemgetter(*srt_key)(v)) for k,v in d.items()}

print(new_d)

Upvotes: 4

tobias_k
tobias_k

Reputation: 82899

First, separate keys and values in the dict

>>> keys, values = zip(*d.items())

Now, zip the values, adding the key-list as the first column

>>> zip(d[u"d"], *values)
[(5, 1, 'g', 9, 5), (1, 4, 'a', 9, 1), (10, 6, 'b', 9, 10), (2, 7, '9', 8, 2)]

Sort the values by first column (the key-list)

>>> sorted(_)
[(1, 4, 'a', 9, 1), (2, 7, '9', 8, 2), (5, 1, 'g', 9, 5), (10, 6, 'b', 9, 10)]

Then zip the result of the sort back and strip the key-column

>>> zip(*_)[1:]
[(4, 7, 1, 6), ('a', '9', 'g', 'b'), (9, 8, 9, 9), (1, 2, 5, 10)]

zip again with the keys to reconstruct the dictionary.

>>> dict(zip(keys, _))
{u'a': (4, 7, 1, 6),
 u'b': (9, 8, 9, 9),
 u'c': ('a', '9', 'g', 'b'),
 u'd': (1, 2, 5, 10)}

Everything put together:

keys, values = zip(*d.items())
new_d = dict(zip(keys, zip(*sorted(zip(d[u"d"], *values)))[1:]))

Upvotes: 4

xnx
xnx

Reputation: 25498

You can build new_d like this:

In [9]: new_d = {}

In [10]: for k in d.keys():
    new_d[k] = [x for (y,x) in sorted(zip(d[u'd'],d[k]), key=lambda pair: pair[0])]
   ....:     

In [11]: new_d
Out[11]: 
{u'a': [4, 7, 1, 6],
 u'b': [9, 8, 9, 9],
 u'c': ['a', '9', 'g', 'b'],
 u'd': [1, 2, 5, 10]}

This approach pairs the items from each list with the list governing the sort order, and sorts the list of pairs by the latter.

Upvotes: 1

Related Questions