【问题标题】:Sort a list by the number of occurrences of the elements in the list [duplicate]按列表中元素的出现次数对列表进行排序[重复]
【发布时间】:2017-06-20 23:06:11
【问题描述】:

我想按列表中元素的出现次数对列表进行排序。
当我使用这种形式时:

A=[2,1,3,4,2,2,3]
A.sort(key=lambda x:A.count(x))  
print(A)

结果不是我想要的:[2, 1, 3, 4, 2, 2, 3].
但是,当我使用sorted 写这样的文章时:

B=sorted(A,key=lambda x:A.count(x))
print(B)

结果是对的:[1, 4, 3, 3, 2, 2, 2].
这种行为的原因是什么?

【问题讨论】:

  • 旁注,您不需要lambda,例如A.sort(key = A.count)
  • 这会返回 A 中每个元素的出现次数:[A.count(element) for element in set(A)]
  • 在此处使用Counter (A.sort(key=collections.Counter(A).get)) 会更有效,并且适用于sortsorted
  • Python 对象分为可变和不可变两种。如果可变对象中的值发生变化,它会影响原始数据。因为list object是可变的,所以数据的索引是动态变化的。

标签: python list sorting


【解决方案1】:

似乎A在就地排序过程中发生了变化,所以你不能在排序过程中依赖A的值。

复制也可以。

A=[2,1,3,4,2,2,3]
B=A[:]
A.sort(key=lambda x:B.count(x))
print(A)

通过python documentation中的这条线确认

CPython 实现细节:在对列表进行排序时,尝试改变甚至检查列表的效果是未定义的。 Python 的 C 实现使列表在持续时间内显示为空,如果它可以检测到列表在排序期间发生了变异,则会引发 ValueError。

【讨论】:

  • 我不确定这是一个完整的答案,似乎更像是一个猜测;)
  • 猜对了:)
  • @Chris_Rands 一个猜测,但现在我在文档中找到了备份 :) 拍摄,接受的答案从一开始就是正确的 :)
【解决方案2】:

我相信这是因为A.sort 在计算时正在修改下面的列表。 sorted() 不会修改列表并因此返回正确的结果。

【讨论】:

    【解决方案3】:

    这是设计和故意的。 CPython 在列表就地排序时暂时“禁止”访问列表,行为是documented here

    CPython 实现细节: 在对列表进行排序时, 试图改变甚至检查列表的效果是 未定义。 Python 的 C 实现使列表显示为空 持续时间,如果它可以检测到列表,则引发 ValueError 在排序过程中发生了变异。

    您可以通过在 key 函数中打印 A 来检查 - 您将获得一个 空列表

    In [2]: def key_function(x):
        ...:     print(A, x)
        ...:     return A.count(x)
        ...: 
    
    In [3]: A.sort(key=key_function)  
    ([], 2)
    ([], 1)
    ([], 3)
    ([], 4)
    ([], 2)
    ([], 2)
    ([], 3)
    

    但是,如果你为 sorted() 这样做:

    In [4]: sorted(A, key=key_function)
    ([2, 1, 3, 4, 2, 2, 3], 2)
    ([2, 1, 3, 4, 2, 2, 3], 1)
    ([2, 1, 3, 4, 2, 2, 3], 3)
    ([2, 1, 3, 4, 2, 2, 3], 4)
    ([2, 1, 3, 4, 2, 2, 3], 2)
    ([2, 1, 3, 4, 2, 2, 3], 2)
    ([2, 1, 3, 4, 2, 2, 3], 3)
    Out[4]: [1, 4, 3, 3, 2, 2, 2]
    

    它也记录在sort() implementation

    /* The list is temporarily made empty, so that mutations performed
     * by comparison functions can't affect the slice of memory we're
     * sorting (allowing mutations during sorting is a core-dump
     * factory, since ob_item may change).
     */.
    

    【讨论】:

    • 这并不是因为它不烂:)
    • 此限制可能不适用于key= 函数。我建议在bugs.python.org 提交错误报告
    • 哇!违反了最小惊讶原则。一个错误将是一个改进,imo。
    • 这听起来不像是我的实现细节。
    【解决方案4】:

    提供内置的sorted creates a list out of the sequence,然后根据关键参数对其进行排序(省略错误检查):

    /* copy sequence provided */
    newlist = PySequence_List(seq);
    
    /* get list.sort for the list object */
    callable = _PyObject_GetAttrId(newlist, &PyId_sort);
    
    /* call it and then return later on */
    v = _PyObject_FastCallKeywords(callable, args + 1, nargs - 1, kwnames);
    

    这基本上转化为 Jean 在他的回答中提供的内容:

    B = list(A)
    B.sort(key=lambda x: A.count(x))
    

    通过复制B 并在key 函数中引用A,这消除了A.sort 施加的限制,它本身不能窥视。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-14
      • 2015-06-30
      • 1970-01-01
      • 1970-01-01
      • 2015-11-14
      相关资源
      最近更新 更多