首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何以完全相同的方式对两个列表(相互引用)进行排序

如何以完全相同的方式对两个列表(相互引用)进行排序
EN

Stack Overflow用户
提问于 2012-03-19 10:35:10
回答 14查看 160.2K关注 0票数 182

假设我有两个列表:

代码语言:javascript
运行
复制
list1 = [3, 2, 4, 1, 1]
list2 = ['three', 'two', 'four', 'one', 'one2']

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

代码语言:javascript
运行
复制
list1 = [1, 1, 2, 3, 4]
list2 = ['one', 'one2', 'two', 'three', 'four']

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

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

EN

回答 14

Stack Overflow用户

回答已采纳

发布于 2012-03-19 10:45:12

解决这个问题的一个经典方法是使用“装饰,排序,取消装饰”的习惯用法,使用python内置的zip函数尤其简单:

代码语言:javascript
运行
复制
>>> 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')

当然,这些不再是列表,但这很容易补救,如果重要的话:

代码语言:javascript
运行
复制
>>> 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行,在我的机器上处理小列表的速度要快一点:

代码语言:javascript
运行
复制
>>> %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

另一方面,对于更大的列表,单行版本可能更快:

代码语言:javascript
运行
复制
>>> %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's suggestion更快一些,但它可能只会更快一点,因为它使用very same DSU idiom internally进行所有基于键的排序。它只是发生在离裸机更近一点的地方。(这显示了zip例程的优化程度有多好!)

我认为zip-based方法更灵活,可读性更好,所以我更喜欢它。

票数 305
EN

Stack Overflow用户

发布于 2012-03-19 10:48:50

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

代码语言:javascript
运行
复制
indexes = range(len(list1))
indexes.sort(key=list1.__getitem__)

要获取给定排序索引的排序列表,请执行以下操作:

代码语言:javascript
运行
复制
sorted_list1 = map(list1.__getitem__, indexes)
sorted_list2 = map(list2.__getitem__, indexes)

在您的示例中,您不应该使用list1list2,而应该使用单个配对列表:

代码语言:javascript
运行
复制
data = [(3, 'three'), (2, 'two'), (4, 'four'), (1, 'one'), (1, 'one2')]

它很容易创建;在Python中很容易排序:

代码语言:javascript
运行
复制
data.sort() # sort using a pair as a key

仅按第一个值排序:

代码语言:javascript
运行
复制
data.sort(key=lambda pair: pair[0])
票数 36
EN

Stack Overflow用户

发布于 2013-10-10 07:04:11

我已经使用senderle给出的答案很长一段时间了,直到我发现了np.argsort。下面是它的工作原理。

代码语言:javascript
运行
复制
# 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]

我发现这个解决方案更直观,而且工作得很好。性能:

代码语言:javascript
运行
复制
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不是最快的,但我发现它更容易使用。

票数 24
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9764298

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档