如何排序两个列表(其中相互引用)在完全相同的方式

假设我有两个列表:

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

如果我运行list1.sort(),它会把它排序到[1,1,2,3,4],但有没有办法让list2同步(所以我可以说4项属于'three')?因此,期望输出为:

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

我的问题是,我有一个相当复杂的程序,它可以很好地处理列表,但我需要开始引用一些数据。我知道这对字典来说是一个完美的情况,但我试图在我的处理中避免字典,因为我确实需要对键值进行排序(如果我必须使用字典,我知道如何使用它们)。

基本上,这个程序的本质是,数据以随机顺序出现(如上面所示),我需要对其进行排序,处理,然后发送结果(顺序不重要,但用户需要知道哪个结果属于哪个键)。我想过先把它放在字典中,然后对列表1排序,但如果不保持顺序,我将无法区分具有相同值的项(这可能会影响将结果传达给用户)。所以理想情况下,一旦我得到了列表,我宁愿想办法把两个列表排序在一起。这可能吗?

201015 次浏览

你可以使用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']

希望这能有所帮助

Schwartzian变换。内置的Python排序是稳定的,所以两个__abc不会造成问题。

>>> 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')]

解决这个问题的一个经典方法是使用“装饰,排序,不装饰”;使用python内置的zip函数特别简单:

>>> 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']

值得注意的是,上述方法可能会为了简洁而牺牲速度;in-place版本占用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

正如quantium7指出的那样,JSF的建议还是快一点,但它可能只会快一点,因为Python对所有基于键的排序都使用在内部非常相同的DSU习惯用法。只是发生在离裸露的金属更近的地方。(这显示了zip例程优化得有多好!)

我认为基于__abc0的方法更灵活,可读性更强,所以我更喜欢它。


注意,当list1中的元素相等时,此方法将最终比较list2中的元素。如果list2中的元素不支持比较,或者比较时不产生布尔值(例如,如果list2是NumPy数组列表),则此操作将失败,如果list2中的元素比较代价非常高,则避免比较可能会更好。

在这种情况下,你可以按照jfs的答案对索引进行排序,或者你可以给排序一个键函数,以避免比较list2的元素:

result1, result2 = zip(*sorted(zip(list1, list2), key=lambda x: x[0]))

同样,当输入为空时,使用zip(*...)作为转置也会失败。如果输入可能为空,则必须单独处理这种情况。

是什么:

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')]

你可以使用值作为键对索引进行排序:

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

要获得给定已排序索引的已排序列表:

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

在你的例子中,你不应该有list1list2,而是一个单独的对列表:

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])

一种方法是通过对单位[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)
我已经使用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不是最快的,但我发现它更容易使用。

你可以在sorted()方法中使用key参数,除非你在list2中有两个相同的值。

代码如下:

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

它根据list1中的对应值对list2进行排序,但请确保在使用此方法时,list2中的任何两个值都不相等,因为list.index()函数给出了第一个值

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

算法解决方案:

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]

__abc2 __abc0 __abc3 __abc1

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

当对另一个列表排序时,另一种保持字符串列表顺序的方法如下:

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


# sort on list1 while retaining order of string list
sorted_list1 = [y for _,y in sorted(zip(list1,list2),key=lambda x: x[0])]
sorted_list2 = sorted(list1)


print(sorted_list1)
print(sorted_list2)

输出

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

我想展开开放的jfs的回答,这对我的问题很有效:将两个列表按第三个装饰列表排序:

我们可以以任何方式创建装饰列表,但在本例中,我们将从两个原始列表之一的元素创建它,我们想要排序:

# say we have the following list and we want to sort both by the algorithms name
# (if we were to sort by the string_list, it would sort by the numerical
# value in the strings)
string_list = ["0.123 Algo. XYZ", "0.345 Algo. BCD", "0.987 Algo. ABC"]
dict_list = [{"dict_xyz": "XYZ"}, {"dict_bcd": "BCD"}, {"dict_abc": "ABC"}]


# thus we need to create the decorator list, which we can now use to sort
decorated = [text[6:] for text in string_list]
# decorated list to sort
>>> decorated
['Algo. XYZ', 'Algo. BCD', 'Algo. ABC']

现在我们可以应用jfs的解决方案对两个列表按第三个排序

# create and sort the list of indices
sorted_indices = list(range(len(string_list)))
sorted_indices.sort(key=decorated.__getitem__)


# map sorted indices to the two, original lists
sorted_stringList = list(map(string_list.__getitem__, sorted_indices))
sorted_dictList = list(map(dict_list.__getitem__, sorted_indices))


# output
>>> sorted_stringList
['0.987 Algo. ABC', '0.345 Algo. BCD', '0.123 Algo. XYZ']
>>> sorted_dictList
[{'dict_abc': 'ABC'}, {'dict_bcd': 'BCD'}, {'dict_xyz': 'XYZ'}]

如果你正在使用numpy,你可以使用np.argsort来获取排序的下标,并将这些下标应用到列表中。这适用于你想要排序的任意数量的列表。

import numpy as np


arr1 = np.array([4,3,1,32,21])
arr2 = arr1 * 10
sorted_idxs = np.argsort(arr1)


print(sorted_idxs)
>>> array([2, 1, 0, 4, 3])


print(arr1[sorted_idxs])
>>> array([ 1,  3,  4, 21, 32])


print(arr2[sorted_idxs])
>>> array([ 10,  30,  40, 210, 320])

如果你需要同步排序超过2个列表,我想建议一个解决方案:

def SortAndSyncList_Multi(ListToSort, *ListsToSync):
y = sorted(zip(ListToSort, zip(*ListsToSync)))
w = [n for n in zip(*y)]
return list(w[0]), tuple(list(a) for a in zip(*w[1]))