对具有多个条件的元组列表进行排序

时间:2013-10-28 19:08:11

标签: python list sorting tuples

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

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

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

  1. 按照元组的第一个元素的值
  2. 对列表进行排序
  3. 接下来,按照元组的第二个元素的长度对列表进行排序(不是值,长度!)。步骤1结束后。
  4. 接下来,按照第1步和第2步完成后元组的第二个元素的值对列表进行排序。
  5. 我的尝试:

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

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

    正确的排序列表应为:

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

    感谢您的帮助。

3 个答案:

答案 0 :(得分:15)

键功能可以返回元组。

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)

答案 1 :(得分:4)

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

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

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

如果你使用集合作为key结果,那么它将使用第一个比较第一个元素进行排序,如果它们相等,那么将比较秒数等等......

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

答案 2 :(得分:2)

正确的解决方案是使用返回元组的key函数,如unutbu的答案所示。然而,还有另一种方法。 Python的排序保证稳定,因此您可以通过不同的键进行多种排序并实现所需的输出。 特别是:

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

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

另请注意,用于排序的算法是自适应的。这意味着当一个序列已经被部分排序时,它可以使用偏序来更有效地排序(通常是线性时间而不是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