给定并行列表,我如何对一个列表进行排序,同时以相同的方式对另一个列表进行排列(重新排列)?

2024-12-05 08:37:00
admin
原创
150
摘要:问题描述:假设我有:list1 = [3, 2, 4, 1, 1] list2 = ['three', 'two', 'four', 'one', 'one2'] 调用list1.sort()将对其进行排序,结果为[1, 1, 2, 3, 4]。但是,我可以list2同步重新排列 ,以获得这样的结果吗?lis...

问题描述:

假设我有:

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

调用list1.sort()将对其进行排序,结果为[1, 1, 2, 3, 4]。但是,我可以list2同步重新排列 ,以获得这样的结果吗?

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

有时,人们会以不同的方式表述问题:给定两个列表,他们希望使用其中一个列表来确定另一个列表的排序顺序 - 即list2按照 中相应值描述的顺序进行排序list1。诀窍在于,这相当于对“键”值list1)进行排序,然后list2以相同的方式重新排列。换句话说,正是这里描述的。然而,另一个问题的一些答案随后会丢弃“排序后的键”。

另请参阅:如何根据列表元素在另一个列表中出现的位置对列表进行排序? - 这是人们希望“基于”另一个列表对一个列表进行排序的另一种常见方式。在尝试关闭重复问题之前,请特别注意检查原始发帖人到底想要什么。一个关键线索:列表的长度是否需要相同?


解决方案 1:

解决这个问题的一个经典方法是使用“装饰、排序、去装饰”的习语,使用 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']

值得注意的是,上述代码可能会为了简洁而牺牲速度;在我的计算机上,就地版本(占用 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基于的方法更灵活,可读性更强,所以我更喜欢它。


请注意,当的元素list1相等时,此方法最终将比较的元素list2。如果的元素list2不支持比较,或者在比较时不产生布尔值(例如,如果list2是 NumPy 数组列表),则此方法将失败,并且如果的元素list2比较成本非常高,最好还是避免比较。

在这种情况下,您可以按照 jfs 的答案中的建议对索引进行排序,或者您可以为排序提供一个避免比较元素的关键函数list2

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

此外,当输入为空时,作为转置的用法zip(*...)会失败。如果您的输入可能为空,则必须单独处理这种情况。

解决方案 2:

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

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

# Or on Python 3, where range does not return a list
indexes = sorted(range(len(list1)), key=list1.__getitem__)

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

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

# Python 3 version, converting map iterator to true list
sorted_list1 = list(map(list1.__getitem__, indexes))
sorted_list2 = list(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])

解决方案 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:

这可以使用 Perl 程序员所称的Schwartzian 变换(也称为装饰-排序-去装饰习语)来实现。内置的 Python 排序是稳定的,因此这两个1s 不会引起问题。

>>> 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:

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

希望这有帮助

解决方案 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:

那么:

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

解决方案 8:

如果您使用 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])

解决方案 9:

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

代码如下:

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

它根据 list1 中的相应值对 list2 进行排序,但要确保在使用它时,list2 中没有两个值的计算结果相等,因为 list.index() 函数给出第一个值

解决方案 10:

根据@pylang对我刚刚关闭的重复问题的回答,必要的算法在流行的第三方库中实现more_itertools,即sort_together。

因此:

from more_itertools import sort_together

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

list1, list2 = sort_together((list1, list2))

解决方案 11:

对另一个列表进行排序时保留字符串列表顺序的另一种方法如下:

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]

解决方案 12:

如果您需要同步对 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]))

解决方案 13:

我想扩展 open 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'}]

解决方案 14:

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

解决方案 15:

算法解决方案:

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

解决方案 16:

在 python 中对两个列表进行排序(按十进制值排序)

a = ['a','b','c','d','e','f']
b = ['0.23','80.00','5.01','6.58','1.38','79.06']
c=sorted(b,key=lambda x:float(x))
d=[]
for i in range(len(a)):
    d.append(a[b.index(c[i])])
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2577  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1553  
  IPD(Integrated Product Development)流程作为一种先进的产品开发管理模式,在众多企业中得到了广泛应用。其中,技术评审与决策评审是IPD流程中至关重要的环节,它们既有明显的区别,又存在紧密的协同关系。深入理解这两者的区别与协同,对于企业有效实施IPD流程,提升产品开发效率与质量具有重要意义...
IPD管理流程   26  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、ClickUp、Freshdesk、GanttPRO、Planview、Smartsheet、Asana、Nifty、HubPlanner、Teamwork。在当今快速变化的商业环境中,项目管理软件已成为企业提升效率、优化资源分配和确保项目按时交付的关键工具。然而...
项目管理系统   21  
  建设工程项目质量关乎社会公众的生命财产安全,也影响着企业的声誉和可持续发展。高质量的建设工程不仅能为使用者提供舒适、安全的环境,还能提升城市形象,推动经济的健康发展。在实际的项目操作中,诸多因素会对工程质量产生影响,从规划设计到施工建设,再到后期的验收维护,每一个环节都至关重要。因此,探寻并运用有效的方法来提升建设工程...
工程项目管理制度   18  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用