6

我目前正在尝试对以下列表进行排序:

list_ = [(1, '0101'), (1, '1010'), (1, '101'), (2, '01'), (2, '010'), (2, '10')]

这些是我想要对其进行排序的步骤:

  1. 按元组的第一个元素的值对列表进行排序
  2. 接下来,在步骤 1 完成后,按元组的第二个元素的长度(不是值,长度!)对列表进行排序。
  3. 接下来,在步骤 1 和步骤 2 完成后,按元组的第二个元素的值对列表进行排序。

我的尝试:

sorted_by_length = sorted(list_, key=len x:x[1])

但是,我收到有关xafter的语法错误key= len。在这种情况下我应该使用什么正确的变量?

正确的排序列表应该是:

sorted_by_length = [(1, '101'), (1, '0101'), (1, '1010'), (2, '01'), (2, '10'), (2, '010')]

谢谢你的帮助。

4

3 回答 3

20

key 函数可以返回一个元组。

sorted_by_length = sorted(list_,
                         key=lambda x: (x[0], len(x[1]), float(x[1])))

这是因为元组是按字典顺序排序的:(元组的第一个元素首先用于排序,然后第二个元素用于打破平局,然后第三个元素用于打破任何剩余的平局。)

请参阅优秀的HOWTO Sort以了解与排序相关的此问题和其他问题的说明。


In [1]: list_ = [(1, '0101'), (1, '1010'), (1, '101'), (2, '01'), (2, '010'), (2, '10')]

In [2]: sorted_by_length = sorted(list_,
                         key=lambda x: (x[0], len(x[1]), float(x[1])))
   ...: 
In [3]: sorted_by_length
Out[3]: [(1, '101'), (1, '0101'), (1, '1010'), (2, '01'), (2, '10'), (2, '010')]

int如果每个元组的第二个元素是二进制中的字符串表示形式,则在排序键中使用int(x, 2)代替。float(x)如果它们打算成为整数的十进制表示,则使用int(x).

于 2013-10-28T19:10:41.517 回答
4

您可以使用返回集合作为结果的键函数进行排序

list_.sort(key=lambda x: [x[0], len(x[1]), x[1]])

key参数指定在进行比较之前对每个列表元素调用的函数。

如果您使用集合作为key结果,那么它将使用首先比较第一个元素(如果它们相等)然后比较第二个元素进行排序,依此类推......

PS据我了解,没有必要将第三项转换为数字类型,因为如果相等,那么对于二进制值,字典和数字排序将给出相同的结果

于 2013-10-28T19:14:32.020 回答
2

正确的解决方案是使用key返回元组的函数,如 unutbu 的答案所示。但是,还有另一种方法。Python的排序保证是稳定的,所以你可以通过不同的key进行多次排序,达到你想要的输出。尤其:

list_.sort(key=lambda x: float(x[1]))
list_.sort(key=lambda x: len(x[1]))
list_.sort(key=lambda x: x[0])

使用 IPython 演示:

In [1]: list_ = [(1, '0101'), (1, '1010'), (1, '101'), (2, '01'), (2, '010'), (2, '10')]

In [2]: list_.sort(key=lambda x: float(x[1]))
   ...: list_.sort(key=lambda x: len(x[1]))
   ...: list_.sort(key=lambda x: x[0])
   ...: 

In [3]: list_
Out[3]: [(1, '101'), (1, '0101'), (1, '1010'), (2, '01'), (2, '10'), (2, '010')]

注意:此解决方案类似于您在问题中描述的三个步骤,步骤相反!最后按主键排序以获得正确的输出。

还要记住,用于排序的算法是自适应的。这意味着当一个序列已经部分排序时,它可以使用部分顺序来更有效地排序(通常在线性时间而不是nlog(n))。当您按多个键排序时,您通常会实现这种偏序,因此多次调用sort()不会花费太多。然而,它高度依赖于密钥和数据。有时它比使用元组作为键更有效,有时它很慢。


时间的一个例子。请注意,这两种解决方案大多需要相同的时间。

In [9]: list_
Out[9]: [(1, '0101'), (1, '1010'), (1, '101'), (2, '01'), (2, '010'), (2, '10')]

In [10]: list_ *= 1000   # better to avoid too small benchmarks.

In [11]: %%timeit
    ...: a = sorted(list_, key=lambda x: (x[0], len(x[1]), float(x[1])))
    ...: 
100 loops, best of 3: 6.04 ms per loop

In [12]: %%timeit
    ...: a = sorted(list_, key=lambda x: float(x[1]))
    ...: a.sort(key=lambda x: len(x[1]))
    ...: a.sort(key=lambda x: x[0])
    ...: 
100 loops, best of 3: 5.72 ms per loop
In [13]: import random
    ...: data = [(random.randint(1, 1000), bin(random.randint(1, 100))[2:]) for _ in range(10000)]
    ...: 

In [14]: %%timeit
    ...: a = sorted(data, key=lambda x: (x[0], len(x[1]), float(x[1])))
    ...: 
100 loops, best of 3: 15.2 ms per loop

In [15]: %%timeit
    ...: a = sorted(data, key=lambda x: float(x[1]))
    ...: a.sort(key=lambda x: len(x[1]))
    ...: a.sort(key=lambda x: x[0])
    ...: 
100 loops, best of 3: 15.1 ms per loop
于 2013-10-28T20:09:25.690 回答