2016-04-12 3 views
4

Поэтому у меня есть два списка:Python: Сортировка двух списков на основе первой с типами None

keys = ['Z', 'X', None, None] 
values = [ 0 , 1 , None, None] 

мне нужно, чтобы быть в состоянии принять эти два списка и сортируют их на основе значения ключей, а затем вернуть его для себя. В идеале, результат будет:

keys = ['X', 'Z', None, None] 
values = [ 1 , 0 , None, None] 

То, что я пытаюсь здесь:

self.keys, self.values = (list(x) for x in zip(*sorted(zip(self.keys, 
          self.values), key=lambda pair: pair[0]))) 

Это прекрасно работает, за исключением того, что он дает мне ошибку:

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

Как могу ли я не сортировать, используя этот метод? Есть ли лучший способ, чем я пытаюсь?

+0

Duplicate? http://stackoverflow.com/questions/12971631/sorting-list-by-an-attribute-that-can-be-none –

+0

Неужели 'None' должен быть больше, чем все? – timgeb

+0

@LauroMoura Этот вопрос близок, но он не использовал метод, который я пытался реализовать. – Avairhn

ответ

0

просто добавить условие для ключа для sorted

keys, values = (list(x) for x in zip(*sorted(zip(keys, values), key=lambda pair: pair[0] if pair[0] is not None else 'temp'))) 

этого MAPS «Темп» любой None значения в списке и в порядке сравнения для отсортированного «Темпа» больше «X» , прописные алфавиты меньше, чем в нижнем регистре

>>> 'temp' < 'X' 
False 
+0

Именно то, что я искал. Благодаря! – Avairhn

0

Если вам нужно, чтобы ваша функция сортировки была последовательной по возвращаемому значению (если нет, вам следует), просто измените ее, как lambda pair: pair[0] or "". Он вернет "" по телефону (None, <WHATEVER>).

В противном случае, пожалуйста, укажите, если None > "1" или нет.

2

Связанный вопрос имеет несколько жизнеспособных подходов, но я думаю, что промах на предпочтительную один, который является для сортировки по ключу вместо скаляра кортежа. Таким образом, мы можем убедиться, что мы сравниваем только сравнимые количества.

Например:

>>> list(zip(keys, values)) 
[('Z', 0), ('X', 1), (None, None), (None, None)] 
>>> sorted(zip(keys, values),key=lambda x: (x[0] is None, x[0])) 
[('X', 1), ('Z', 0), (None, None), (None, None)] 

Это работает, потому что для каждой пары, мы получим кортеж в BOOL и строку:

>>> for pair in zip(keys, values): 
...  print(pair, (pair[0] is None, pair[0])) 
...  
('Z', 0) (False, 'Z') 
('X', 1) (False, 'X') 
(None, None) (True, None) 
(None, None) (True, None) 

Из-за того, как работает сравнение кортеж, мы будем только когда-либо приходилось сравнивать в пределах групп True или False, поэтому None никогда не будет сравниваться со строкой. А так как False < Правда, мы получим пары «Нет» в конце.

+0

Мне нравится эта реализация, и я очень склонен голосовать за нее правильным ответом. Однако я не хочу изменять представление ключей и значений из двух отдельных списков. Если бы у меня не было этого требования, ваш ответ был бы правильным. – Avairhn

+0

@Avairhn: erm, вам не нужно. Как и в вашем исходном коде, вы пишете 'sorted (zip (self.keys, self.values), key = lambda pair: pair [0])', вместо этого вы можете использовать вышеупомянутую ключевую функцию. – DSM

0

Другим решением будет иметь некоторый объект, который никогда не меньше любого другого объекта, и использовать его для сравнения, если вы столкнулись с None.

>>> def sortkey(pair): 
...  if pair[0] is not None: 
...   return pair[0] 
...  return type('', (object,), {'__lt__': lambda x,y: False})() 
... 
>>> keys = ['Z', 'X', None, None] 
>>> values = [ 0 , 1 , None, None] 
>>> k, v = map(list, zip(*sorted(zip(keys, values), key=sortkey))) 
>>> k 
['X', 'Z', None, None] 
>>> v 
[1, 0, None, None] 
0

Простое решение будет включать определение своего собственного ключа

sort_fxn = lambda pair: '' if pair[0] is None else pair[0] 
list(zip(*sorted(zip(keys, values), key=sort_fxn))) 

значение None не расположены в конце сорта, но другие ключи сортируются:

[(None, None, 'X', 'Z'), (None, None, 1, 0)] 

Если значения None имеют решающее значение для вашей сортировки, вы можете закодировать все свои строки в байтах и ​​использовать сравнение массива байтов :

sort_fxn = lambda pair: bytes([255]) if pair[0] is None else pair[0].encode('utf-8') 

Примечание: это занимает в два раза больше времени для сортировки из-за заказа. (3 против 1,5 микросекунды). Если вас беспокоит такая оптимизация.

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