Python 如何使用列表理解删除列表中相邻的重复元素?

Python 如何使用列表理解删除列表中相邻的重复元素?,python,list,list-comprehension,Python,List,List Comprehension,有没有一种方法可以在python中使用列表理解来过滤列表中相邻的重复项 这里有一个例子来说明我的意思: >>> xs = [1,2,2,3] >>> print added.reAdj(xs) [1,2,3] 通过搜索SE发现一个类似但略有不同的问题:是否可以从列表中删除所有重复项,但没有明确询问涉及列表理解的解决方案。使用列表理解的动机具体地遵循了认知。用户建议使用set()函数或标准循环: result = [] most_recent_elem = N

有没有一种方法可以在python中使用列表理解来过滤列表中相邻的重复项

这里有一个例子来说明我的意思:

>>> xs = [1,2,2,3]
>>> print added.reAdj(xs)
[1,2,3]
通过搜索SE发现一个类似但略有不同的问题:是否可以从列表中删除所有重复项,但没有明确询问涉及列表理解的解决方案。使用列表理解的动机具体地遵循了认知。用户建议使用set()函数或标准循环:

result = []
most_recent_elem = None
for e in xs:
    if e != most_recent_elem:
        result.append(e)
        most_recent_elem = e
set()
建议无法满足任务要求,因为删除了非相邻的重复项,而循环有效但冗长

这似乎是一种安全引用列表中下一个元素的方法,需要如下理解

[x for x in xs if x != **x.next()**]
有什么想法吗?

您可以使用:


itertools.groupby
返回迭代器。通过迭代,您将得到一个键,组对。(如果未指定
函数,则
将成为一项,否则
函数的返回值)
group
是一个迭代器,它将通过应用
key
函数生成分组的项(如果未指定,将分组相同的值)

导入itertools >>>it=itertools.groupby([1,2,2,3]) >>>它 >>>对于键,请在其中输入: ... 打印(键) ... 印刷品(玻璃钢) ... 1. 2. 3. >>>it=itertools.groupby([1,2,2,3]) >>>对于键,请在其中输入: ... 打印(列表(grp)) ... [1] [2, 2] [3] 在上面的解决方案中,我只使用了
,因为问题并不关心有多少项相邻。

您可以使用@AChampion建议的解决方案:

xs = [1,2,2,2,1,1]
In [115]: [n for i, n in enumerate(xs) if i==0 or n != xs[i-1]]
Out[115]: [1, 2, 1]

如果是第一个,则返回该列表项;如果不等于上一个,则返回下一个列表项。由于对
if
语句的延迟计算,它将起作用。

您可以使用一种不太详细的循环解决方案:

>>> result = xs[:1]
>>> for e in xs:
        if e != result[-1]:
            result.append(e)
或:


使用itertools菜谱中的两两(zip_最长)可以方便地检查下一个元素:

import itertools as it

def pairwise(iterable):
    a, b = it.tee(iterable)
    next(b, None)
    return it.zip_longest(a, b, fillvalue=object())   # izip_longest for Py2

>>> xs = [1,2,2,3]
>>> [x for x, y in pairwise(xs) if x != y]
[1, 2, 3]
>>> xs = [1,2,2,2,2,3,3,3,4,5,6,6]
>>> [x for x, y in pairwise(xs) if x != y]
[1, 2, 3, 4, 5, 6]
这个怎么样:

>>> l = [1,1,2,3,4,4,4,4,5,6,3,3,5,5,7,8,8,8,9,1,2,3,3,3,10,10]
>>> 
>>> o = []
>>> p = None
>>> for n in l:
        if n == p:
            continue
        o.append(n)
        p = n    

>>> o
[1, 2, 3, 4, 5, 6, 3, 5, 7, 8, 9, 1, 2, 3, 10]
显然,上述解决方案比OP的更详细,因此这里有一个替代使用from
itertools
模块的解决方案:

>>> l
[1, 1, 2, 3, 4, 4, 4, 4, 5, 6, 3, 3, 5, 5, 7, 8, 8, 8, 9, 1, 2, 3, 3, 3, 10, 10]
>>> from itertools import zip_longest
>>> o = [p for p,n in zip_longest(l,l[1:]) if p != n] #By default fillvalue=None
>>> o
[1, 2, 3, 4, 5, 6, 3, 5, 7, 8, 9, 1, 2, 3, 10]

这是否意味着即使
[1,2,2,2,2,3,3,4,5,6,6]-->[1,2,3,4,5,6]
?@IronFist,您理解正确。“这是期望的结果。”阿坎皮恩说。谢谢你的链接,但据我所知,这张海报并没有特别要求回答涉及列表理解的问题。我最初的问题帖子包含了一个循环解决方案。稍微挑剔:它删除了尾随的
None
值。注意:但不是一个int列表问题。并且可以通过向
zip\u longest
添加
fillvalue
来避免,修复了@安东波波夫。请在取得进展时更新。不幸的是,Stefan Pochmann提出的案例不起作用,因为你的解决方案在其他方面非常优雅。@Antonprotopov-请,请,请将AChampion建议的解决方案纳入你的答案中。这比对
itertools
中的某个不可理解函数的不可理解的调用要好得多。@DavidHammen
groupby
很简单也很好,你不应该因为自己的不足而责备它。@antopropov-现在你得到了一个负一。众所周知,
xs[-1]
是python中数组的最后一个元素。如果你没有纠正这一点,你的答案就大错特错了。似乎错误是显而易见的。在接下来的几个小时里,如果有人提出任何其他问题,我会接受这个答案。这个答案是有效的,但它的逻辑与OP完全相同,只是稍微有点冗长。@AlexanderHuszagh。。是的…我忘了详细更新的那一点。。使用
zip_longest
在没有排序输入的情况下使用
groupby
是很奇怪的,但我想这在这个特定的用例中是非常合适的
import itertools as it

def pairwise(iterable):
    a, b = it.tee(iterable)
    next(b, None)
    return it.zip_longest(a, b, fillvalue=object())   # izip_longest for Py2

>>> xs = [1,2,2,3]
>>> [x for x, y in pairwise(xs) if x != y]
[1, 2, 3]
>>> xs = [1,2,2,2,2,3,3,3,4,5,6,6]
>>> [x for x, y in pairwise(xs) if x != y]
[1, 2, 3, 4, 5, 6]
>>> l = [1,1,2,3,4,4,4,4,5,6,3,3,5,5,7,8,8,8,9,1,2,3,3,3,10,10]
>>> 
>>> o = []
>>> p = None
>>> for n in l:
        if n == p:
            continue
        o.append(n)
        p = n    

>>> o
[1, 2, 3, 4, 5, 6, 3, 5, 7, 8, 9, 1, 2, 3, 10]
>>> l
[1, 1, 2, 3, 4, 4, 4, 4, 5, 6, 3, 3, 5, 5, 7, 8, 8, 8, 9, 1, 2, 3, 3, 3, 10, 10]
>>> from itertools import zip_longest
>>> o = [p for p,n in zip_longest(l,l[1:]) if p != n] #By default fillvalue=None
>>> o
[1, 2, 3, 4, 5, 6, 3, 5, 7, 8, 9, 1, 2, 3, 10]