The Oddler The Oddler - 7 months ago 22
Python Question

Python: Ordering list of string and None based on other list?

I have two lists of equal length, one containing numbers, the other strings and

None
. I want to order them by descending numbers, keeping the other one in sync.

Before the second list could only contain string (so no
None
elements), and I used this code:

weights, urls = zip(*sorted(zip(unordered_weights, unordered_urls), reverse=True))


The numbers are in the "weights" array, the strings in the "urls" array. This worked fine.

However, now that I allow
None
in my strings list, I get the following error:

TypeError: unorderable types: str() < NoneType()


For some reason it's also trying to sort the strings, I guess in case the weights are the same. How can I fix this?

I'm using Python 3, I read that in Python 2
None
came before any string, but now it gives an error. The order of strings with the same weight doesn't matter.

Answer

Sorting tuples is done lexicographically - first the first elements are compared, if they are equal then the second, which in your case can be None. You can sort using only the weights by extracting it as the sorting key through the key argument to sorted():

weights, urls = zip(*sorted(zip(unordered_weights, unordered_urls), reverse=True, key=lambda x: x[0]))

Observe:

In [1]: unordered_urls = ['b', 'a', None, 'c', None]
In [2]: unordered_weights = [1, 0, 0, 5, 2]  # the 'a' and None have the same weight
In [3]: weights, urls = zip(*sorted(zip(unordered_weights, unordered_urls), reverse=True))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-61fb3631580a> in <module>()
----> 1 weights, urls = zip(*sorted(zip(unordered_weights, unordered_urls), reverse=True))

TypeError: unorderable types: str() < NoneType()

In [4]: weights, urls = zip(*sorted(zip(unordered_weights, unordered_urls), reverse=True, key=lambda x: x[0]))
In [5]: weights
Out[5]: (5, 2, 1, 0, 0)
In [6]: urls
Out[6]: ('c', None, 'b', 'a', None)