是否可以以完全相同的方式对两个列表(相互引用)进行排序?

时间:2021-07-10 12:21:38

Okay, this may not be the smartest idea but I was a bit curious if this is possible. Say I have two lists:

好吧,这可能不是最聪明的想法,但如果可能的话,我有点好奇。说我有两个清单:

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

If I run list1.sort(), it'll sort it to [1,1,2,3,4] but is there a way to get to keep list2 in sync as well(so I can say item 4 belongs to 'three')? My problem is I have a pretty complex program that is working fine with lists but I sort of need to start referencing some data. I know this is a perfect situation for dictionaries but I'm trying to avoid dictionaries in my processing because I do need to sort the key values(if I must use dictionaries I know how to use them).

如果我运行list1.sort(),它会将它排序为[1,1,2,3,4]但是有一种方法可以保持list2同步(所以我可以说第4项属于'三')?我的问题是我有一个非常复杂的程序,可以正常使用列表,但我需要开始引用一些数据。我知道这对字典来说是一个完美的情况,但是我试图在处理中避免使用字典,因为我确实需要对键值进行排序(如果我必须使用字典,我知道如何使用它们)。

Basically the nature of this program is, the data comes in a random order(like above), I need to sort it, process it and then send out the results(order doesn't matter but users need to know which result belongs to which key). I thought about putting it in a dictionary first, then sorting list one but I would have no way of differentiating of items in the with the same value if order is not maintained(it may have an impact when communicating the results to users). So ideally, once I get the lists I would rather figure out a way to sort both lists together. Is this possible?

基本上这个程序的本质是,数据以随机顺序出现(如上所述),我需要对其进行排序,处理它然后发出结果(顺序无关紧要但是用户需要知道哪个结果属于哪个键)。我想先将它放在字典中,然后对列表进行排序,但如果不维护订单,我就无法区分具有相同值的项目(在将结果传达给用户时可能会产生影响)。理想情况下,一旦我得到列表,我宁愿想出一种方法来将两个列表排序在一起。这可能吗?

8 个解决方案

#1


136  

One classic approach to this problem is to use the "decorate, sort, undecorate" idiom, which is especially simple using python's built-in zip function:

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

These of course are no longer lists, but that's easily remedied, if it matters:

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

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

It's worth noting that the above may sacrifice speed for terseness; the in-place version, which takes up 3 lines, is a tad faster on my machine for small lists:

值得注意的是,上述可能会牺牲简洁的速度;就地版本,占用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

On the other hand, for larger lists, the one-line version could be faster:

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

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

As Quantum7 points out, JSF's suggestion is a bit faster still, but it will probably only ever be a little bit faster, because Python uses the very same DSU idiom internally for all key-based sorts. It's just happening a little closer to the bare metal. (This shows just how well optimized the zip routines are!)

正如Quantum7指出的那样,JSF的建议还是要快一点,但它可能只会更快一些,因为Python在内部对所有基于密钥的排序都使用了相同的DSU惯用法。它只是发生在靠近裸金属的地方。 (这显示了zip例程的优化程度!)

I think the zip-based approach is more flexible and is a little more readable, so I prefer it.

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

#2


18  

You can sort indexes using values as keys:

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

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

To get sorted lists given sorted indexes:

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

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

In your case you shouldn't have list1, list2 but rather a single list of pairs:

在你的情况下,你不应该有list1,list2,而是一个对的列表:

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

It is easy to create; it is easy to sort in Python:

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

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

Sort by the first value only:

仅按第一个值排序:

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

#3


10  

Schwartzian transform. The built-in Python sorting is stable, so the two 1s don't cause a problem.

施瓦茨变换。内置的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')]

#4


8  

I have used the answer given by senderle for a long time until I discovered np.argsort. Here is how it works.

我已经使用了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]

I find this solution more intuitive, and it works really well. The perfomance:

我发现这个解决方案更直观,而且效果非常好。性能:

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

Even though np.argsort isn't the fastest one, I find it easier to use.

即使np.argsort不是最快的,我发现它更容易使用。

#5


3  

What about:

关于什么:

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


2  

One way is to track where each index goes to by sorting the identity [0,1,2,..n]

一种方法是通过对标识[0,1,2,... n]进行排序来跟踪每个索引的去向。

This works for any number of lists.

这适用于任意数量的列表。

Then move each item to its position. Using splices is best.

然后将每个项目移动到其位置。使用拼接是最好的。

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

index = 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']"

Note we could have iterated the lists without even sorting them:

请注意,我们可以迭代列表,甚至不对它们进行排序:

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

#7


1  

You can use the zip() and sort() functions to accomplish this:

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

Hope this helps

希望这可以帮助

#8


0  

You can use the key argument in sorted() method unless you have two same values in list2.

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

The code is given below:

代码如下:

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

It sorts list2 according to corresponding values in list1, but make sure that while using this, no two values in list2 evaluate to be equal because list.index() function give the first value

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

#1


136  

One classic approach to this problem is to use the "decorate, sort, undecorate" idiom, which is especially simple using python's built-in zip function:

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

These of course are no longer lists, but that's easily remedied, if it matters:

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

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

It's worth noting that the above may sacrifice speed for terseness; the in-place version, which takes up 3 lines, is a tad faster on my machine for small lists:

值得注意的是,上述可能会牺牲简洁的速度;就地版本,占用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

On the other hand, for larger lists, the one-line version could be faster:

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

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

As Quantum7 points out, JSF's suggestion is a bit faster still, but it will probably only ever be a little bit faster, because Python uses the very same DSU idiom internally for all key-based sorts. It's just happening a little closer to the bare metal. (This shows just how well optimized the zip routines are!)

正如Quantum7指出的那样,JSF的建议还是要快一点,但它可能只会更快一些,因为Python在内部对所有基于密钥的排序都使用了相同的DSU惯用法。它只是发生在靠近裸金属的地方。 (这显示了zip例程的优化程度!)

I think the zip-based approach is more flexible and is a little more readable, so I prefer it.

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

#2


18  

You can sort indexes using values as keys:

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

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

To get sorted lists given sorted indexes:

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

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

In your case you shouldn't have list1, list2 but rather a single list of pairs:

在你的情况下,你不应该有list1,list2,而是一个对的列表:

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

It is easy to create; it is easy to sort in Python:

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

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

Sort by the first value only:

仅按第一个值排序:

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

#3


10  

Schwartzian transform. The built-in Python sorting is stable, so the two 1s don't cause a problem.

施瓦茨变换。内置的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')]

#4


8  

I have used the answer given by senderle for a long time until I discovered np.argsort. Here is how it works.

我已经使用了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]

I find this solution more intuitive, and it works really well. The perfomance:

我发现这个解决方案更直观,而且效果非常好。性能:

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

Even though np.argsort isn't the fastest one, I find it easier to use.

即使np.argsort不是最快的,我发现它更容易使用。

#5


3  

What about:

关于什么:

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


2  

One way is to track where each index goes to by sorting the identity [0,1,2,..n]

一种方法是通过对标识[0,1,2,... n]进行排序来跟踪每个索引的去向。

This works for any number of lists.

这适用于任意数量的列表。

Then move each item to its position. Using splices is best.

然后将每个项目移动到其位置。使用拼接是最好的。

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

index = 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']"

Note we could have iterated the lists without even sorting them:

请注意,我们可以迭代列表,甚至不对它们进行排序:

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

#7


1  

You can use the zip() and sort() functions to accomplish this:

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

Hope this helps

希望这可以帮助

#8


0  

You can use the key argument in sorted() method unless you have two same values in list2.

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

The code is given below:

代码如下:

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

It sorts list2 according to corresponding values in list1, but make sure that while using this, no two values in list2 evaluate to be equal because list.index() function give the first value

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