将相等的列表元素组合在一起



这是将相等元素组合在一起(使它们连续出现在列表中)的好方法吗?

>>> 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个结果

最新更新