简体   繁体   English

将相同的列表元素放在一起

[英]Bring equal list elements together

Is this an alright way to bring equal elements together (make them appear consecutively in the list)?这是将相同元素放在一起(使它们连续出现在列表中)的好方法吗?

>>> 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]

Edit: List where it allegedly doesn't work (see comments):编辑:列出据称不起作用的地方(见评论):

>>> 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]

Just use list.sort :只需使用list.sort

a = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8]
a.sort()
print(a)

Output:输出:

[1, 1, 2, 2, 2, 7, 8, 8, 8, 8]

If u want it in descending order, then pass reverse = True to list.sort :如果您希望按降序排列,则将reverse = True传递给list.sort

a = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8]
a.sort(reverse = True)
print(a)

Output:输出:

[8, 8, 8, 8, 7, 2, 2, 2, 1, 1]

Another solution, giving no guarantee on the order of the output, but that is O(n) instead O(n*log(n)) for the solution using sort: count the values, and create a new list with the corresponding counts for each value:另一种解决方案,不保证输出的顺序,但对于使用 sort: count the values, and create a new list with相应的计数的解决方案,使用 O(n) 而不是 O(n*log(n))每个值:

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]

As suggested by @Manuel, there is a Counter method that I had never noticed, Counter.elements() :正如@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

So, to get an output in original order, and in O(n), the code would be simply:因此,要按原始顺序在 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]

Why/how it works, and about this possibly being an undefined implementation detail:为什么/如何工作,以及这可能是一个未定义的实现细节:

The iterator starts at the end :迭代器从最后开始

                             iterator
                                ↓
a = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8]
x = undefined

Then the for loop asks the iterator for an item.然后for循环向迭代器询问一个项目。 After getting the last 8, the iterator decreases its index into the list and returns the 8 ( code ), which the for loop stores in x .在获得最后 8 个之后,迭代器将其索引减少到列表中并返回 8( 代码), for循环将其存储在x So now we have:所以现在我们有:

                             ↓
a = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8]
x = 8

Then a.remove(x) removes the first 8, which shifts all later items to the left:然后a.remove(x)删除8 个,将所有后面的项目向左移动:

                             ↓
a = [2, 7, 1, 2, 8, 1, 8, 2, 8]
x = 8

And a.append(x) appends it at the end:并且a.append(x)将它附加到最后:

                             ↓
a = [2, 7, 1, 2, 8, 1, 8, 2, 8, 8]
x = 8

Then the for loop gets the next item from the iterator, which is the same 8 as before, only at the lower index:然后for循环从迭代器中获取下一项,与之前的 8 相同,只是在较低的索引处:

                          ↓
a = [2, 7, 1, 2, 8, 1, 8, 2, 8, 8]
x = 8 (same one again)

The remove again removes the first 8 (which was originally the second 8): remove再次删除8 个(最初是第二个8):

                          ↓
a = [2, 7, 1, 2, 1, 8, 2, 8, 8]

And it gets appended:它被附加:

                          ↓
a = [2, 7, 1, 2, 1, 8, 2, 8, 8, 8]

The next round moves the originally third 8 to the end:下一轮将原来的第三个8 移到最后:

                       ↓
a = [2, 7, 1, 2, 1, 2, 8, 8, 8, 8]

And then finally the originally fourth 8 (which we've been finding over and over again) moves as well:最后,最初的第四个8(我们一遍又一遍地发现)也移动了:

                    ↓
a = [2, 7, 1, 2, 1, 2, 8, 8, 8, 8]

The same then happens to the 2's, 1's and the 7, so we end up with:同样的情况也发生在 2、1 和 7 上,所以我们最终得到:

a = [8, 8, 8, 8, 2, 2, 2, 1, 1, 7]

JBernardo commented that it "could be undefined behavior on a different python implementation" . JBernardo 评论说它“可能是不同 python 实现的未定义行为” I guess it could be, but I'd blame that implementation.我想它可能是,但我会责怪那个实现。 The Python reference documentation notes (although about the forward iterator): Python 参考文档说明(尽管关于前向迭代器):

There is a subtlety when the sequence is being modified by the loop (this can only occur for mutable sequences, eg lists).当循环修改序列时有一个微妙之处(这只能发生在可变序列,例如列表)。 An internal counter is used to keep track of which item is used next, and this is incremented on each iteration.内部计数器用于跟踪下一个使用哪个项目,并且在每次迭代时递增。 When this counter has reached the length of the sequence the loop terminates.当这个计数器达到序列的长度时,循环终止。 This means that if the suite deletes the current (or a previous) item from the sequence, the next item will be skipped (since it gets the index of the current item which has already been treated).这意味着如果套件从序列中删除当前(或前一个)项目,则将跳过下一个项目(因为它获取已处理的当前项目的索引)。 Likewise, if the suite inserts an item in the sequence before the current item, the current item will be treated again the next time through the loop.同样,如果套件在当前项目之前的序列中插入一个项目,则当前项目将在下一次循环中再次被处理。

And that's not marked as a CPython implementation detail, which the Python documentation does at plenty of other places: 261 results for googling site:docs.python.org/3/ "CPython implementation detail"这并没有标记为 CPython 实现细节,Python 文档在很多其他地方都这样做了:谷歌搜索的 261 个结果站点:docs.python.org/3/“CPython implementation detail”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM