【问题标题】:What is the difference between `sorted(list)` vs `list.sort()`?`sorted(list)` 与 `list.sort()` 有什么区别?
【发布时间】:2014-04-21 22:48:56
【问题描述】:

list.sort() 对列表进行排序并替换原始列表,而sorted(list) 返回列表的排序副本,而不更改原始列表。

  • 什么时候比另一个更受欢迎?
  • 哪个更有效?多少?
  • 执行list.sort() 后,列表能否恢复为未排序状态?

【问题讨论】:

  • 如果您(不小心)在字符串参数上调用 sorted() 但认为它是一个列表,您会得到一个列表结果,而不是字符串sorted("abcd", reverse=True) 给出 @ 987654327@不是"dcba"
  • 对于寻找重复的人的注意事项:许多与list.sort() 相关的问题返回None,而不是新的list,在这里被欺骗了,当他们最好被欺骗时更具体的Why does “return list.sort()” return None, not the list?

标签: python list sorting copy in-place


【解决方案1】:

注意:sort() 和 sorted() 最简单的区别是:sort() 不返回任何值,而 sorted() 返回一个可迭代的列表。

sort() 不返回任何值。

sort() 方法只是按特定顺序对给定列表的元素进行排序 - 升序或降序,而不返回任何值。

sort()方法的语法是:

list.sort(key=..., reverse=...)

或者,您也可以使用 Python 的内置函数 sorted() 出于同样的目的。 sorted 函数返回排序列表

 list=sorted(list, key=..., reverse=...)

【讨论】:

    【解决方案2】:

    这里有几个简单的例子来看看行动的不同:

    在此处查看数字列表:

    nums = [1, 9, -3, 4, 8, 5, 7, 14]
    

    在此列表上调用sorted 时,sorted 将制作列表的副本。 (意味着您的原始列表将保持不变。)

    让我们看看。

    sorted(nums)
    

    返回

    [-3, 1, 4, 5, 7, 8, 9, 14]
    

    再看nums

    nums
    

    我们看到了原始列表(未更改且未排序。)。 sorted没有改变原来的列表

    [1, 2, -3, 4, 8, 5, 7, 14]
    

    采用相同的nums 列表并对其应用sort 函数,将更改实际列表。

    让我们看看。

    从我们的nums 列表开始,以确保内容仍然相同。

    nums
    
    [-3, 1, 4, 5, 7, 8, 9, 14]
    
    nums.sort()
    

    现在原始 nums 列表已更改,查看 nums 我们看到原始列表已更改并且现在已排序。

    nums
    [-3, 1, 2, 4, 5, 7, 8, 14]
    

    【讨论】:

    • 感谢您更深入地展示原始与副本
    【解决方案3】:

    sorted(list)list.sort() 有什么区别?

    • list.sort 就地改变列表并返回 None
    • sorted 接受任何可迭代并返回一个新列表,已排序。

    sorted 相当于这个 Python 实现,但 CPython 内置函数应该运行得更快,因为它是用 C 编写的:

    def sorted(iterable, key=None):
        new_list = list(iterable)    # make a new list
        new_list.sort(key=key)       # sort it
        return new_list              # return it
    

    什么时候用哪个?

    • 如果您不希望保留原始排序顺序,请使用 list.sort (因此,您将能够在内存中就地重用列表。)以及何时 您是列表的唯一所有者(如果列表由其他代码共享 如果你改变它,你可能会在使用该列表的地方引入错误。)
    • 当您想要保留原始排序顺序或当您 希望创建一个只有您的本地代码拥有的新列表。

    list.sort() 后可以检索列表的原始位置吗?

    否 - 除非您自己制作副本,否则该信息会丢失,因为排序是就地完成的。

    “哪个更快?又快多少?”

    为了说明创建新列表的后果,请使用 timeit 模块,这是我们的设置:

    import timeit
    setup = """
    import random
    lists = [list(range(10000)) for _ in range(1000)]  # list of lists
    for l in lists:
        random.shuffle(l) # shuffle each list
    shuffled_iter = iter(lists) # wrap as iterator so next() yields one at a time
    """
    

    这是我们随机排列的 10000 个整数列表的结果,正如我们在这里看到的,我们已经反驳了 an older list creation expense myth

    Python 2.7

    >>> timeit.repeat("next(shuffled_iter).sort()", setup=setup, number = 1000)
    [3.75168503401801, 3.7473005310166627, 3.753129180986434]
    >>> timeit.repeat("sorted(next(shuffled_iter))", setup=setup, number = 1000)
    [3.702025591977872, 3.709248117986135, 3.71071034099441]
    

    Python 3

    >>> timeit.repeat("next(shuffled_iter).sort()", setup=setup, number = 1000)
    [2.797430992126465, 2.796825885772705, 2.7744789123535156]
    >>> timeit.repeat("sorted(next(shuffled_iter))", setup=setup, number = 1000)
    [2.675589084625244, 2.8019039630889893, 2.849375009536743]
    

    经过一些反馈后,我决定需要另一个具有不同特征的测试。在这里,我为每次迭代 1,000 次提供相同的随机排序列表,长度为 100,000。

    import timeit
    setup = """
    import random
    random.seed(0)
    lst = list(range(100000))
    random.shuffle(lst)
    """
    

    我将这种更大的差异解释为来自 Martijn 提到的复制,但它并没有在此处较旧的更流行的答案中占主导地位,这里的时间增加仅为 10% 左右

    >>> timeit.repeat("lst[:].sort()", setup=setup, number = 10000)
    [572.919036605, 573.1384446719999, 568.5923951]
    >>> timeit.repeat("sorted(lst[:])", setup=setup, number = 10000)
    [647.0584738299999, 653.4040515829997, 657.9457361929999]
    

    我还在一个小得多的类型上运行了上述内容,发现新的 sorted 复制版本在 1000 长度上仍然需要大约 2% 的运行时间。

    Poke 也运行了自己的代码,代码如下:

    setup = '''
    import random
    random.seed(12122353453462456)
    lst = list(range({length}))
    random.shuffle(lst)
    lists = [lst[:] for _ in range({repeats})]
    it = iter(lists)
    '''
    t1 = 'l = next(it); l.sort()'
    t2 = 'l = next(it); sorted(l)'
    length = 10 ** 7
    repeats = 10 ** 2
    print(length, repeats)
    for t in t1, t2:
        print(t)
        print(timeit(t, setup=setup.format(length=length, repeats=repeats), number=repeats))
    

    他发现对于 1000000 长度的排序,(运行 100 次)类似的结果,但只增加了大约 5% 的时间,这是输出:

    10000000 100
    l = next(it); l.sort()
    610.5015971539542
    l = next(it); sorted(l)
    646.7786222379655
    

    结论:

    使用sorted 进行排序的大型列表复制可能会主导差异,但排序本身会主导操作,围绕这些差异组织代码将是过早的优化。当我需要一个新的数据排序列表时,我会使用sorted,当我需要对列表进行就地排序时,我会使用list.sort,并让它决定我的用法。

    【讨论】:

    • 发电机设置很好,但我不会得出结论说你太快打破了神话。事实仍然是sorted() 必须分配一个新的列表对象并复制引用;其余代码路径相同。看看您是否可以使用更大的列表运行相同的测试。将其与仅创建列表副本进行比较,看看您是否可以复制您发现的差异等。
    【解决方案4】:

    .sort() 函数将新列表的值直接存储在列表变量中;所以你的第三个问题的答案是否定的。 此外,如果您使用 sorted(list) 执行此操作,那么您可以使用它,因为它没有存储在 list 变量中。有时 .sort() 方法也充当函数,或者说它接受参数。

    您必须将 sorted(list) 的值显式存储在变量中。

    同样对于短数据处理速度也没有区别;但是对于长列表;您应该直接使用 .sort() 方法进行快速工作;但你将再次面临不可逆转的行动。

    【讨论】:

    • ".sort() 函数将新列表的值直接存储在列表变量中" 嗯?什么新名单?没有新名单。 list.sort() 方法对列表对象进行就地排序。
    • 另外,这是什么意思? “有时 .sort() 方法充当函数,或者说它接受参数。”
    • 我所说的新列表是修改后的列表,.sort() 只是将修改后的列表存储到同一个变量中。
    • 是的,绝对有时.sort() 方法需要参数,并充当函数。我们也称它为方法,因为它是列表数据类型的属性。
    • 如果我的概念中存在某种错误,请告诉我,我会寻找并改进我的概念以及我的答案。谢谢
    【解决方案5】:

    sorted() 返回一个 new 排序列表,原始列表不受影响。 list.sort() 对列表进行就地排序,改变列表索引,并返回None(与所有就地操作一样)。

    sorted() 适用于任何可迭代对象,而不仅仅是列表。字符串、元组、字典(你会得到键)、生成器等,返回一个包含所有元素的列表,排序。

    • 当你想要改变列表时使用list.sort(),当你想要一个新的排序对象返回时使用sorted()。当您想对可迭代的东西进行排序时,请使用sorted(),而不是列表尚未

    • 对于列表,list.sort()sorted() 快,因为它不必创建副本。对于任何其他可迭代对象,您别无选择。

    • 不,您无法检索原始位置。一旦你打电话给list.sort(),原来的订单就消失了。

    【讨论】:

    • 一般来说,当一个python函数返回None时,这表明操作已经到位,这就是为什么当你想打印list.sort()时它返回None。跨度>
    【解决方案6】:

    主要区别在于sorted(some_list)返回一个新的list

    a = [3, 2, 1]
    print sorted(a) # new list
    print a         # is not modified
    

    some_list.sort()对列表进行排序就地

    a = [3, 2, 1]
    print a.sort() # in place
    print a         # it's modified
    

    注意,由于a.sort() 不返回任何内容,print a.sort() 将打印None


    list.sort() 后可以检索到列表原始位置吗?

    不,因为它修改了原始列表。

    【讨论】:

    • print a.sort() 不会打印任何内容。
    • 它将打印None,我会澄清这一点。
    猜你喜欢
    • 1970-01-01
    • 2016-04-26
    • 1970-01-01
    • 2012-04-15
    • 1970-01-01
    • 1970-01-01
    • 2011-05-04
    • 1970-01-01
    相关资源
    最近更新 更多