【问题标题】:Sorting a list of tuples with multiple conditions对具有多个条件的元组列表进行排序
【发布时间】:2013-11-07 17:10:13
【问题描述】:

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

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

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

正确的排序列表应该是:

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

感谢您的帮助。

【问题讨论】:

  • value of of the second element 是什么意思?您希望该步骤按字典顺序排列吗?还是应该将该字符串解释为二进制整数值?
  • key 参数需要一个从列表中获取元素并返回要排序的键值的函数。 len x:x[1] 是无效的语法。 len 用括号调用。要创建一个在调用 len 之前首先获取元组的第二项的函数,请使用 lambda:key=lambda x:len(x[1])。下面的答案显示了如何修改它以通过一键功能满足您的三个条件。

标签: python list sorting tuples


【解决方案1】:

正确的解决方案是使用返回元组的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')]

注意:此解决方案类似于您在问题中描述的三个步骤但步骤相反!按主键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

【讨论】:

  • 它有效!如此简单!我在尝试几个小时之前只使用 for in range 和 while 对其进行排序,...谢谢大家的快速回答! :)
【解决方案2】:

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)。

【讨论】:

  • 它有效!如此简单!我在尝试几个小时之前只使用 for in range 和 while 对其进行排序,...谢谢大家的快速回答! :)
【解决方案3】:

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

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

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

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

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

【讨论】:

  • 关于“没有必要将第三项转换为数字类型...”,因为字符串的长度不等,字典顺序和数字顺序将不一样。例如'10111' 将排序为小于'11'。
  • 是的,但长度优先级更高,所以11 无论如何都应该在10111 之前。据我所知,唯一不符合此规则的是负数。
  • 谢谢,我错过了长度比较的含义。在我看来,'010' 的排序大于'11' 确实很奇怪。也许 OP 真正需要的是key=lambda x:(x[0], bin(x[1], 2)))。
  • 它有效!如此简单!我在尝试几个小时之前只使用 for in range 和 while 对其进行排序,...谢谢大家的快速回答! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-25
  • 2017-08-25
  • 1970-01-01
  • 2021-07-14
  • 2021-07-26
相关资源
最近更新 更多