2013-03-25 3 views
3

Я новичок здесь python, и меня поразила довольно простая проблема - и я ищу наиболее эффективный способ решить эту проблему. Итак, у меня есть 5 списков:сортировка нескольких списков в python на основе сортировки одного списка

a,b,c,d,score 

, где приведенные выше списки имеют одинаковый размер (500 в моем случае). a,b,c,d - это строковые списки, а score - это список int.

Что бы я хотел сделать, это сортировать a,b,c,d на основе возрастания или убывания Сортировка score. Итак, сначала я хотел бы отсортировать score на основе нисходящего шаблона, а затем отсортировать соответствующие элементы в a,b,c,d на основе отсортированного списка баллов (в том же порядке).

Я думал о enumerate, чтобы добиться этого, но мне интересно, можно ли использовать здесь itertools, чтобы сделать его быстрее и эффективнее.

Любые указания относительно того, как это может быть достигнуто, будут очень благодарны & & Извините, если это вопрос 101.

+1

См. Подобные вопросы здесь: http: // stackoverflow.com/questions/6618515/sorting-list-on-values-from-another-list – alecxe

+0

, который, в свою очередь, является обманом http://stackoverflow.com/q/9543211/989121. Однако, если списки большие и python == 2, то 'it.izip' будет лучше, чем просто' zip'. – georg

ответ

7
sorted_lists = sorted(izip(a, b, c, d, score), reverse=True, key=lambda x: x[4]) 
a, b, c, d, score = [[x[i] for x in sorted_lists] for i in range(5)] 

На этом первом этапе zip списки вместе. Это берет первый элемент из каждого списка и помещает их в кортеж, добавляет этот кортеж в новый список, затем делает то же самое для второго элемента в каждом списке и т. Д. Затем мы сортируем этот список кортежей пятым элементом (это от анонимной функции, переданной в аргумент key). Мы установили reverse=True, чтобы список нисходил.

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

a, b, c, d, score = izip(*sorted(izip(a, b, c, d, score), reverse=True, 
         key=lambda x: x[4])) 

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

def sort_lists_by(lists, key_list=0, desc=False): 
    return izip(*sorted(izip(*lists), reverse=desc, 
       key=lambda x: x[key_list])) 
+0

благодарит EML за ваше замечательное решение - я просто задавался вопросом - может ли быть более общее решение, например, где 'x [4]' и 'range (5)' можно избежать? Я спрашиваю об этом, потому что у вас может быть более 5 списков .. и я не уверен, что это помогает мне понять, когда значения жестко закодированы :( – AJW

+0

Отредактировано для добавления общей функции. 'Range (5)' находится здесь, чтобы обозначить индекс каждого элемента в подсписках, поэтому мы можем разбить каждый дополнительный список после того, как мы скрепили их вместе. 'x [4]' просто указать список, по которому мы сортируем все остальные. общая функция, они заменяются. – EML

+0

Интересно, что 'zip' переносит вложенные списки. Аналогичная функциональность для транспонирования массивов. – Eike

2

Если вы делаете много численной работы или манипуляции массива, это может быть стоит посмотреть в использовании numpy. Эта проблема очень легко решается с помощью Numpy массива:

In [1]: import numpy as np 
In [2]: a = ['hi','hello'] 
In [3]: b = ['alice','bob'] 
In [4]: c = ['foo','bar'] 
In [5]: d = ['spam','eggs'] 
In [6]: score = [42,17] 

Исходя из этого, составьте список кортежей в формате (a,b,c,d,score) и хранить каждый с DTYPE (str,str,str,str,int), и вы можете даже дать им имена ('a','b','c','d','score') доступа к ним позже:

In [7]: data = np.array(zip(a,b,c,d,score), 
    ...:   dtype = [('a','S5'),('b','S5'),('c','S5'),('d','S5'),('score',int)] 
    ...: ) 

In [8]: data 
Out[8]: 
array([('hi', 'alice', 'foo', 'spam', 42), 
     ('hello', 'bob', 'bar', 'eggs', 17)], 
     dtype=[('a', 'S5'), ('b', 'S5'), ('c', 'S5'), ('d', 'S5'), ('score', '<i8')]) 

преимущество этого массива является то, что вы можете получить доступ ко всем «списки» (полей) по их имени:

In [9]: data['a'] 
Out[9]: 
array(['hi', 'hello'], 
     dtype='|S5') 

In [10]: data['score'] 
Out[10]: array([42, 17]) 

Чтобы отсортировать объявления, введите имя поля, которую хотите сортировать по:

In [11]: sdata = np.sort(data, order='score') 

In [12]: sdata 
Out[12]: 
array([('hello', 'bob', 'bar', 'eggs', 17), 
     ('hi', 'alice', 'foo', 'spam', 42)], 
     dtype=[('a', 'S5'), ('b', 'S5'), ('c', 'S5'), ('d', 'S5'), ('score', '<i8')]) 

In [13]: sdata['b'] 
Out[13]: 
array(['bob', 'alice'], 
     dtype='|S5') 
Смежные вопросы