2016-04-16 4 views
2

У меня есть два списка одинаковой длины, один из которых содержит числа, остальные строки и None. Я хочу заказать их по нисходящим числам, поддерживая синхронизацию другого. МассивPython: список списка строк и None, основанный на другом списке?

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

Число в «весах» массив, строках в «URL»:

Прежде чем второй список может содержать только строку (так что никаких None элементов), и я использовал этот код , Это отлично работает.

Однако теперь, когда я позволяю None в моем списке строк, я получаю следующее сообщение об ошибке:

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

По какой-то причине он также пытается отсортировать строки, я думаю, в случае весов одинаковы. Как я могу это исправить?

Я использую Python 3, я прочитал, что в Python 2 None пришел перед любой строкой, но теперь он дает ошибку. Порядок строк с одинаковым весом не имеет значения.

ответ

5

Сортировка кортежей выполняется лексикографически - сначала сравниваются первые элементы, если они равны, а затем второй, что в вашем случае может быть None. Вы можете сортировать, используя только гири, извлекая его в качестве ключа сортировки через key аргумент в sorted():

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

Наблюдайте:

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) 
+0

Очень приятно, спасибо большое! –

4

Python будет использовать второй элемент в каждом кортеже (ваша строка или None значения), если первый элемент равна между двумя кортежами:

>>> (42, 'foo') < (42, None) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unorderable types: str() < NoneType() 

Вы можете вставить тай-брейк:

from itertools import count 

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

count() iterable object вставляет целые числа, начиная с 0; когда два веса одинаковы, Python затем сравнивает эти целые числа. Поскольку они всегда отличаются друг от друга, элементы в третьей позиции никогда не будут сравниваться друг с другом. Поскольку счет увеличивается монотонно, сортировка остается стабильной в противном случае, два элемента с одинаковым весом сохраняются в одном и том же относительном порядке.

Или вы могли бы сказать sorted() только смотреть на первый элемент:

from operator import itemgetter 
weights, urls = zip(*sorted(zip(unordered_weights, unordered_urls), 
          reverse=True, key=itemgetter(0))) 

Теперь две равные веса остались в том же порядке, тоже, потому что алгоритм сортировки Питон (TimSort) устойчива по умолчанию.

+0

Я пытаюсь понять этот код, не могли бы вы объяснить, что '' 'делает здесь? Я googled и узнал, что это оператор «splat», но я не совсем понимаю, что это цель. – Keatinge

+2

@Racialz: он распаковывает список «кортежей» в отдельные аргументы функции 'zip()'. Поэтому '[(42, 0, 'foo'), (42, 2, None), (24, 1, 'bar')]' передается 'zip()', как если бы ему давались 3 отдельных аргумента. 'zip()' затем объединяет все элементы из каждого аргумента в новые кортежи; все первые вместе в одном, все второе в другом и т. д., поэтому вы получаете последовательность '(42, 42, 24), (0, 2, 1), ('foo', None, 'bar') '.Другими словами, транспонирование строк и столбцов. –

+0

Спасибо, что помогает alot – Keatinge

Смежные вопросы