【问题标题】:Python: list.sort() query when list contains different element typesPython:list.sort() 查询列表包含不同元素类型时
【发布时间】:2014-01-19 06:33:29
【问题描述】:

问候 Pythonic 世界。学习 Python 3.3 的第 4 天,我遇到了 list.sort 的一个奇怪属性。

我创建了一个包含五个元素的列表:四个字符串,中间有一个数字。由于混合类型,试图让list.sort 工作会出现预期错误:

>>> list = ['b', 'a', 3, 'd', 'c']
>>> list.sort()
Traceback (innermost last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: int() < str()
>>> list
['b', 'a', 3, 'd', 'c']

列表没有改变。

但后来我把数字移到最后,再次使用 list.sort,得到了这个:

>>> list = ['b', 'a', 'd', 'c', 3]
>>> list.sort()
Traceback (innermost last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: int() < str()
>>> list
['a', 'b', 'c', 'd', 3]

好的,一个错误。但该列表已自行排序,将数字踢到最后。我在这个网站或 Langtangen 找不到任何解释。这种行为是否有一些根本原因?它在某些情况下有用吗?

【问题讨论】:

  • 我假设python在开始排序之前不会对元素进行类型检查,成功交换了一些元素,然后在比较两种不兼容的类型时引发错误。
  • Python 对小列表使用二进制排序。所以这就是为什么它能够在得到数字之前对前几个进行排序。然后你得到了错误
  • 没有,列表本身没有完全排序,只有少数能够成功比较的项目被移动到适当的位置。一旦 python 识别出您正在比较不同类型的项目,操作就会停止。
  • 你想避免使用list作为变量名,它会屏蔽内置的list
  • @RyanHaining - 谢谢你的建议。它最初以其他文本为前缀,我将其删除。以后会注意的。

标签: python list sorting python-3.x


【解决方案1】:

我最近遇到了同样的问题,不想将所有内容都转换为字符串,所以我这样做了,希望对您有所帮助:)

list = ["a", 1, False, None, "b", (1,3), (1, 'a'),(1, [None, False]), True, 3, False]

type_weights = {}
for element in list:
    if type(element) not in type_weights:
        type_weights[type(element)] = len(type_weights)

print(sorted(list, key=lambda element: (type_weights[type(element)], str(element))))

它应该返回如下内容: ['a', 'b', 1, 3, False, False, True, None, (1, 'a'), (1, 3), (1, [None, False])]

它应该适用于任何数据类型(包括自定义类)

【讨论】:

    【解决方案2】:

    来自 Python 3 docs

    此方法对列表进行就地排序,仅使用

    文档不保证任何特定行为,但元素很可能会被部分排序。无论发生异常时它们的顺序是什么,并且此顺序可能因实现而异,或者可能(但不太可能)程序的两次后续运行。

    如果您想尝试对项目进行排序而不用担心重新排序,您可以使用sorted 内置函数,该函数将返回一个新列表而不是修改原始列表。

    >>> seq = ['b', 'a', 3, 'd', 'c']
    >>> try:
    ...     seq = sorted(seq) # if sorted fails, result won't be assigned
    ... except Exception: # you may only want TypeError
    ...     pass
    ...
    >>> seq 
    ['b', 'a', 3, 'd', 'c'] # list unmodified
    

    编辑: 向每个人说类似的话

    一旦看到两种不同的类型就会引发异常

    我知道您可能已经意识到这种说法过于简单化了,但我认为如果不清楚,就会引起混淆。举个明显的例子,您可以混合使用intfloat 对列表进行排序。

    以下示例包含两个类AB,它们通过各自的__lt__ 方法支持相互比较。它显示了这两种类型的混合列表,使用list.sort() 排序,然后按排序顺序打印,没有引发异常:

    class A:
        def __init__(self, value):
            self.a = value
    
        def __lt__(self, other):
            if isinstance(other, B):
                return self.a < other.b
            else:
                return self.a < other.a
    
        def __repr__(self):
            return repr(self.a)
    
    class B:
        def __init__(self, value):
            self.b = value
    
        def __lt__(self, other):
            if isinstance(other, A):
                return self.b < other.a
            else:
                return self.b < other.b
    
        def __repr__(self):
            return repr(self.b)
    
    seq = [A(10), B(2), A(8), B(16), B(9)]
    seq.sort()
    print(seq)
    

    这个的输出是:

    [2, 8, 9, 10, 16]
    

    了解其中的每一个细节并不重要。这只是为了说明混合类型列表可以与list.sort()一起使用,如果所有部分都在那里

    【讨论】:

    • “...处于部分修改状态”说明了一切。将来最好远离这种情况。我的猜测是它查看第一个元素,读取它的类型,然后沿着列表进行比较(按顺序排序),直到找到具有不同类型的元素,然后停止。很抱歉用我自己的话重复你的回答——这有助于我学习。谢谢。
    • @ShaneMHewitt 不一定要检查类型,如果您有两个使用 __lt__ 方法定义自己的类,可以将另一个作为参数,那么它没有理由失败。当您使用key 时,这一点会更加明显。 key 函数也可以处理所有类型相关的决定,请考虑 seq.sort(key=len)。这适用于由字符串、字典、集合和其他列表组成的列表。
    • @ShaneMHewitt 我已经修改了我的答案以显示一个示例,一个包含两种不同类型的列表与list.sort()
    • 尚未完成课程,因此我将阅读这些内容。这是否意味着理论上您可以对包含许多不同类类型的列表进行排序(对不起,如果我使用了错误的词)?示例:使用您上面的系统,我可以对不包含子列表的列表进行排序,只包含一串字母、整数和浮点数吗?我知道“3”排在“a”之前,依此类推,但数字 3 排在最后。只是大声思考。
    • @ShaneMHewitt 是的。您可以将key 函数传递给list.sort,列表中的每个元素都将传递给该键函数,该函数将返回一些值,然后进行比较。 key=len 是一个常见的,因为 len 是内置的,并且会根据容器的大小对容器进行排序。你可以def你自己的键函数,它会给出你想要的任何行为。我可以想到几个方法。用键排序需要一些研究
    【解决方案3】:

    我通过假设我知道列表中的数据类型来写下面的答案,可能效率不高。我的想法是根据数据类型将给定列表划分为子列表,然后对每个单独的列表进行排序并合并。

    input= ['b', 'a', 3, 'd', 'c']
    strs = list(filter(lambda x : type(x) ==str,input))
    ints = list(filter(lambda x: type(x) == int, input))
    
    output = sorted(strs) + sorted(ints)
    

    【讨论】:

    • 将方法扩展到 str 和 int 之外的任意类型?
    【解决方案4】:

    取决于数据需要如何排序,但这样的事情可以工作

    l = ['a',3,4,'b']
    sorted([str(x) for x in l])
    ['3', '4', 'a', 'b']
    

    【讨论】:

    • 一般来说,人们不想改变数据类型只是为了让数据按顺序排列
    【解决方案5】:

    这并不罕见。只需sort() 不检查列表是否包含一致的数据类型,而是尝试 进行排序。因此,一旦您的元素位于末尾,它就会在最近被分析,因此算法确实在 发现错误之前对列表的一部分进行了排序。

    不,它没有用,因为它在很大程度上取决于实现的排序机制。

    【讨论】:

    • Dziękuję lejlot - 像这样的部分排序有助于可视化幕后实际发生的事情。我以后会远离这个。
    猜你喜欢
    • 2018-07-24
    • 1970-01-01
    • 2020-03-26
    • 2013-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-13
    • 2012-04-12
    相关资源
    最近更新 更多