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

Python 对具有多个条件的元组列表进行排序,python,list,sorting,tuples,Python,List,Sorting,Tuples,我目前正在尝试对以下列表进行排序: list_ = [(1, '0101'), (1, '1010'), (1, '101'), (2, '01'), (2, '010'), (2, '10')] 我想采取以下步骤对其进行排序: 根据元组的第一个元素的值对列表进行排序 接下来,在步骤1完成后,按照元组第二个元素的长度对列表进行排序(不是值,而是长度!) 接下来,在步骤1和步骤2完成后,根据元组的第二个元素的值对列表进行排序 我的尝试: sorted_by_length = sorted(lis

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

list_ = [(1, '0101'), (1, '1010'), (1, '101'), (2, '01'), (2, '010'), (2, '10')]
我想采取以下步骤对其进行排序:

  • 根据元组的第一个元素的值对列表进行排序
  • 接下来,在步骤1完成后,按照元组第二个元素的长度对列表进行排序(不是值,而是长度!)
  • 接下来,在步骤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')]
    

    谢谢您的帮助。

    键函数可以返回元组

    sorted_by_length = sorted(list_,
                             key=lambda x: (x[0], len(x[1]), float(x[1])))
    
    这是因为元组是按字典顺序排序的:(元组的第一个元素用于先排序,然后第二个元素用于断开关系,然后第三个元素用于断开任何剩余的关系。)

    有关此问题以及与排序相关的其他问题的说明,请参见“优秀”部分




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

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

    list_.sort(key=lambda x: [x[0], len(x[1]), x[1]])
    
    参数,指定在进行比较之前对每个列表元素调用的函数

    如果将集合用作
    结果,则将使用第一个比较元素对其进行排序,如果第一个元素相等,则将比较第二个元素,依此类推


    另外,据我所知,没有必要将第三项转换为数字类型,因为如果相等,那么对于二进制值,字典和数字排序将给出相同的结果,正确的解决方案是使用返回元组的
    函数,如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')]
    
    注意:此解决方案类似于您在问题中描述的三个步骤
    ,但步骤是相反的!最后按主键排序以获得正确的输出

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

    第二个元素的值是什么意思?你想让那一步是按字典写的吗?还是应该将该字符串解释为二进制整数值?
    key
    参数需要一个函数,该函数从列表中获取一个元素并返回一个键值进行排序
    lenx:x[1]
    是无效语法
    len
    用括号调用。要使函数在调用
    len
    之前首先获取元组的第二项,请使用lambda:
    key=lambda x:len(x[1])
    。下面的答案显示了如何通过一个键函数修改此项以满足您的三个标准。关于“无需将第三项转换为数字类型…”,由于字符串的长度不相等,字典和数字顺序将不相同。例如
    '10111'
    将排序为小于
    '11'
    。是的,但长度具有更大的优先级,因此
    11
    无论如何都应该在
    10111
    之前。据我所知,唯一不符合这个规则的是负数。谢谢,我错过了长度比较的含义。对我来说,
    '010'
    的排序要比
    '11'
    的排序要大,这似乎很奇怪。也许OP真正需要的是
    key=lambda x:(x[0],bin(x[1],2))
    。它可以工作!这么简单!之前我花了好几个小时试图在范围内对其进行排序,而,。。。谢谢大家的快速回答!!:)它起作用了!这么简单!之前我花了好几个小时试图在范围内对其进行排序,而,。。。谢谢大家的快速回答!!:)它起作用了!这么简单!之前我花了好几个小时试图在范围内对其进行排序,而,。。。谢谢大家的快速回答!!:)
    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