Можно ли сортировать два списка (которые ссылаются друг на друга) точно так же?

Хорошо, это может быть не самая умная идея, но мне было немного любопытно, если это возможно. Скажем, у меня есть два списка:

list1 = [3,2,4,1, 1]
list2 = [three, two, four, one, one2]

Если я запустил list1.sort(), он будет сортировать его до [1,1,2,3,4], но есть ли способ сохранить синхронизацию list2 (так что я могу сказать, что элемент 4 принадлежит "три" )? Моя проблема заключается в том, что у меня довольно сложная программа, которая отлично работает со списками, но мне нужно начинать ссылаться на некоторые данные. Я знаю, что это идеальная ситуация для словарей, но я стараюсь избегать словарей в моей обработке, потому что мне нужно сортировать ключевые значения (если я должен использовать словари, которые я знаю, как их использовать).

В основном характер этой программы заключается в том, что данные поступают в случайном порядке (например, выше), мне нужно отсортировать его, обработать, а затем отправить результаты (заказ не имеет значения, но пользователи должны знать, какой результат принадлежит к ключу). Я подумал о том, чтобы сначала поместить его в словарь, а затем отсортировать список, но у меня не было бы возможности дифференцировать элементы с тем же значением, если порядок не поддерживается (это может повлиять на передачу результатов пользователям). Поэтому в идеале, как только я получу списки, я предпочел бы выяснить способ сортировки обоих списков. Возможно ли это?

Ответ 1

Один классический подход к этой проблеме - использовать "украшать, сортировать, дебекорировать" идиому, что особенно просто с использованием встроенной функции zip на основе python:

>>> list1 = [3,2,4,1, 1]
>>> list2 = ['three', 'two', 'four', 'one', 'one2']
>>> list1, list2 = zip(*sorted(zip(list1, list2)))
>>> list1
(1, 1, 2, 3, 4)
>>> list2 
('one', 'one2', 'two', 'three', 'four')

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

>>> list1, list2 = (list(t) for t in zip(*sorted(zip(list1, list2))))
>>> list1
[1, 1, 2, 3, 4]
>>> list2
['one', 'one2', 'two', 'three', 'four']

Стоит отметить, что вышеизложенное может пожертвовать скоростью для терпения; версия на месте, которая занимает 3 строки, немного медленнее на моей машине для небольших списков:

>>> %timeit zip(*sorted(zip(list1, list2)))
100000 loops, best of 3: 3.3 us per loop
>>> %timeit tups = zip(list1, list2); tups.sort(); zip(*tups)
100000 loops, best of 3: 2.84 us per loop

С другой стороны, для больших списков однострочная версия может быть быстрее:

>>> %timeit zip(*sorted(zip(list1, list2)))
100 loops, best of 3: 8.09 ms per loop
>>> %timeit tups = zip(list1, list2); tups.sort(); zip(*tups)
100 loops, best of 3: 8.51 ms per loop

Как указывает Quantum7, предложение JSF немного быстрее, но, вероятно, это будет только когда-либо немного быстрее, потому что Python использует та же самая идиома DSU внутри для всех видов на основе ключей. Это просто немного приближается к голым металлам. (Это показывает, насколько хорошо оптимизированы подпрограммы zip!)

Я думаю, что подход на основе zip более гибкий и немного читаем, поэтому я предпочитаю его.

Ответ 2

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

indexes = range(len(list1))
indexes.sort(key=list1.__getitem__)

Получить отсортированные списки с отсортированными индексами:

sorted_list1 = map(list1.__getitem__, indexes)
sorted_list2 = map(list2.__getitem__, indexes)

В вашем случае вы не должны иметь list1, list2, а скорее один список пар:

data = [(3, 'three'), (2, 'two'), (4, 'four'), (1, 'one'), (1, 'one2')]

Легко создать; его легко сортировать в Python:

data.sort() # sort using a pair as a key

Сортировка только по первому значению:

data.sort(key=lambda pair: pair[0])

Ответ 3

Я использовал ответ, полученный senderle в течение длительного времени, пока не обнаружил np.argsort. Вот как это работает.

# idx works on np.array and not lists.
list1 = np.array([3,2,4,1])
list2 = np.array(["three","two","four","one"])
idx   = np.argsort(list1)

list1 = np.array(list1)[idx]
list2 = np.array(list2)[idx]

Я нахожу это решение более интуитивным, и оно работает очень хорошо. Производительность:

def sorting(l1, l2):
    # l1 and l2 has to be numpy arrays
    idx = np.argsort(l1)
    return l1[idx], l2[idx]

# list1 and list2 are np.arrays here...
%timeit sorting(list1, list2)
100000 loops, best of 3: 3.53 us per loop

# This works best when the lists are NOT np.array
%timeit zip(*sorted(zip(list1, list2)))
100000 loops, best of 3: 2.41 us per loop

# 0.01us better for np.array (I think this is negligible)
%timeit tups = zip(list1, list2); tups.sort(); zip(*tups)
100000 loops, best for 3 loops: 1.96 us per loop

Несмотря на то, что np.argsort не самый быстрый, мне легче его использовать.

Ответ 4

преобразование Шварца. Встроенная сортировка Python стабильна, поэтому два 1 не вызывают проблемы.

>>> l1 = [3, 2, 4, 1, 1]
>>> l2 = ['three', 'two', 'four', 'one', 'second one']
>>> zip(*sorted(zip(l1, l2)))
[(1, 1, 2, 3, 4), ('one', 'second one', 'two', 'three', 'four')]

Ответ 5

Как насчет:

list1 = [3,2,4,1, 1]
list2 = ['three', 'two', 'four', 'one', 'one2']

sortedRes = sorted(zip(list1, list2), key=lambda x: x[0]) # use 0 or 1 depending on what you want to sort
>>> [(1, 'one'), (1, 'one2'), (2, 'two'), (3, 'three'), (4, 'four')]

Ответ 6

Одним из способов является отслеживание того, куда идет каждый индекс, путем сортировки идентификаторов [0,1,2,.. n]

Это работает для любого количества списков.

Затем переместите каждый элемент на свою позицию. Использование сростков лучше всего.

list1 = [3,2,4,1, 1]
list2 = ['three', 'two', 'four', 'one', 'one2']

index = list(range(len(list1)))
print(index)
'[0, 1, 2, 3, 4]'

index.sort(key = list1.__getitem__)
print(index)
'[3, 4, 1, 0, 2]'

list1[:] = [list1[i] for i in index]
list2[:] = [list2[i] for i in index]

print(list1)
print(list2)
'[1, 1, 2, 3, 4]'
"['one', 'one2', 'two', 'three', 'four']"

Обратите внимание, что мы могли бы перебирать списки, даже не сортируя их:

list1_iter = (list1[i] for i in index)

Ответ 7

Вы можете использовать ключевой аргумент в методе sorted(), если у вас нет двух одинаковых значений в list2.

Код приведен ниже:

sorted(list2, key = lambda x: list1[list2.index(x)]) 

Он сортирует list2 в соответствии с соответствующими значениями в list1, но убедитесь, что при его использовании никакие два значения в list2 не считаются равными, потому что функция list.index() дает первое значение

Ответ 8

Вы можете использовать функции zip() и sort() для выполнения этого:

Python 2.6.5 (r265:79063, Jun 12 2010, 17:07:01)
[GCC 4.3.4 20090804 (release) 1] on cygwin
>>> list1 = [3,2,4,1,1]
>>> list2 = ['three', 'two', 'four', 'one', 'one2']
>>> zipped = zip(list1, list2)
>>> zipped.sort()
>>> slist1 = [i for (i, s) in zipped]
>>> slist1
[1, 1, 2, 3, 4]
>>> slist2 = [s for (i, s) in zipped]
>>> slist2
['one', 'one2', 'two', 'three', 'four']

Надеюсь, что это поможет

Ответ 9

newsource=[];newtarget=[]
for valueT in targetFiles:
    for valueS in sourceFiles:
            l1=len(valueS);l2=len(valueT);
            j=0
            while (j< l1):
                    if (str(valueT) == valueS[j:l1]) :
                            newsource.append(valueS)
                            newtarget.append(valueT)
                    j+=1

Ответ 10

алгоритмическое решение:

list1 = [3,2,4,1, 1]
list2 = ['three', 'two', 'four', 'one', 'one2']


lis = [(list1[i], list2[i]) for i in range(len(list1))]
list1.sort()
list2 = [x[1] for i in range(len(list1)) for x in lis if x[0] == i]

Выходы: -> Скорость выхода: 0.2s

>>>list1
>>>[1, 1, 2, 3, 4]
>>>list2
>>>['one', 'one2', 'two', 'three', 'four']