这是将相等元素组合在一起(使它们连续出现在列表中)的好方法吗?
>>> a = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8]
>>> for x in reversed(a):
a.remove(x)
a.append(x)
>>> a
[8, 8, 8, 8, 2, 2, 2, 1, 1, 7]
编辑:列出据称不起作用的地方(见评论):
>>> a = [2, 7, 1, 1, 8, 2, 8, 1, 8, 2, 8]
>>> for x in reversed(a):
a.remove(x)
a.append(x)
>>> a
[8, 8, 8, 8, 2, 2, 2, 1, 1, 1, 7]
只需使用list.sort
:
a = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8]
a.sort()
print(a)
输出:
[1, 1, 2, 2, 2, 7, 8, 8, 8, 8]
如果要按降序排列,请将reverse = True
传递给list.sort
:
a = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8]
a.sort(reverse = True)
print(a)
输出:
[8, 8, 8, 8, 7, 2, 2, 2, 1, 1]
另一种解决方案,不保证输出的顺序,但对于使用 sort: 计算值,并创建一个新列表,其中包含每个值的相应计数:
from collections import Counter
a = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8]
counts = Counter(a)
out = []
for value, count in counts.items():
out.extend([value]*count)
print(out)
# [2, 2, 2, 7, 1, 1, 8, 8, 8, 8]
正如@Manuel所建议的,有一个我从未注意到的Counter
方法,Counter.elements():
Return an iterator over elements repeating each as many times as its count. Elements are returned in the order first encountered
因此,要以原始顺序和 O(n) 格式获取输出,代码将很简单:
from collections import Counter
a = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8]
out = list(Counter(a).elements())
print(out)
# [2, 2, 2, 7, 1, 1, 8, 8, 8, 8]
为什么/如何工作,这可能是一个未定义的实现细节:
迭代器从末尾开始:
iterator
↓
a = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8]
x = undefined
然后,for
循环向迭代器询问一个项目。在得到最后的 8 后,迭代器将其索引减少到列表中并返回 8(代码),for
循环存储在x
中。所以现在我们有:
↓
a = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8]
x = 8
然后a.remove(x)
删除前8 个,这会将所有后面的项目向左移动:
↓
a = [2, 7, 1, 2, 8, 1, 8, 2, 8]
x = 8
a.append(x)
最后附加了它:
↓
a = [2, 7, 1, 2, 8, 1, 8, 2, 8, 8]
x = 8
然后for
循环从迭代器中获取下一项,它与之前相同,只是在较低的索引处:
↓
a = [2, 7, 1, 2, 8, 1, 8, 2, 8, 8]
x = 8 (same one again)
remove
再次删除了前8 个(最初是第二个8):
↓
a = [2, 7, 1, 2, 1, 8, 2, 8, 8]
它被附加:
↓
a = [2, 7, 1, 2, 1, 8, 2, 8, 8, 8]
下一轮将原来的第三个8移到最后:
↓
a = [2, 7, 1, 2, 1, 2, 8, 8, 8, 8]
最后,最初的第四个8(我们一遍又一遍地发现)也移动了:
↓
a = [2, 7, 1, 2, 1, 2, 8, 8, 8, 8]
同样的情况也发生在 2、1 和 7 上,所以我们最终得到:
a = [8, 8, 8, 8, 2, 2, 2, 1, 1, 7]
JBernardo评论说,它"可能是不同python实现上的未定义行为"。我想可能是,但我会责怪这种实现。Python 参考文档注释(虽然是关于前向迭代器的):
当序列被循环修改时,有一个微妙之处(这只能发生在可变序列上,例如列表)。内部计数器用于跟踪接下来使用哪个项目,并在每次迭代时递增。当此计数器达到序列的长度时,循环终止。这意味着,如果套件从序列中删除当前(或上一个)项,则将跳过下一项(因为它获取已处理的当前项的索引)。同样,如果套件在当前项之前的序列中插入一个项,则下次通过循环将再次处理当前项。
而且这并没有被标记为CPython实现细节,Python文档在很多其他地方都是这样做的:谷歌搜索site:docs.python.org/3/"CPython实现细节"的261个结果