如何使用列表理解删除列表中相邻的重复元素?
How to remove adjacent duplicate elements in a list using list comprehensions?
有没有办法在 python 中使用列表推导来过滤列表中的 相邻 个重复项?
这是我的意思的一个例子:
>>> xs = [1,2,2,3]
>>> print added.reAdj(xs)
[1,2,3]
通过 SE 搜索显示 earlier inquiry asking a similar but slightly different question: whether all duplicates could be removed from a list, but not explicitly asking for solutions involving list comprehensions. The motivation for using list comprehensions specifically follows a recognition of their advantages over traditional for loops。用户建议使用 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
:
>>> import itertools
>>> [key for key, grp in itertools.groupby([1, 2, 2, 3])]
[1, 2, 3]
itertools.groupby
returns 一个迭代器。通过迭代它,你会得到一个密钥,组对。 (如果没有指定 key
函数,key
将是一个项目,否则 key
函数的 return 值)。 group
是一个迭代器,它将产生通过应用 key
函数分组的项目(如果未指定,相同的值将被分组)
>>> import itertools
>>> it = itertools.groupby([1, 2, 2, 3])
>>> it
<itertools.groupby object at 0x7feec0863048>
>>> for key, grp in it:
... print(key)
... print(grp)
...
1
<itertools._grouper object at 0x7feec0828ac8>
2
<itertools._grouper object at 0x7feec0828b00>
3
<itertools._grouper object at 0x7feec0828ac8>
>>> it = itertools.groupby([1, 2, 2, 3])
>>> for key, grp in it:
... print(list(grp))
...
[1]
[2, 2]
[3]
上面的解法,我只用了key
,因为这个问题不关心有多少项目是相邻的。
您可以将 list comprehension
and enumerate
与@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]
该列表理解 return 项(如果它是第一个)或者如果它不等于前一个则用于后续项。由于 if
语句的惰性评估,它会起作用。
您可以使用更简洁的循环解决方案:
>>> result = xs[:1]
>>> for e in xs:
if e != result[-1]:
result.append(e)
或者:
>>> result = []
>>> for e in xs:
if e not in result[-1:]:
result.append(e)
使用 itertools 方法中的成对使用(使用 zip_longest)可以让您轻松检查下一个元素:
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 的更冗长,所以这里有一个替代方案,使用 itertools
模块中的 zip_longest
:
>>> 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]
有没有办法在 python 中使用列表推导来过滤列表中的 相邻 个重复项?
这是我的意思的一个例子:
>>> xs = [1,2,2,3]
>>> print added.reAdj(xs)
[1,2,3]
通过 SE 搜索显示 earlier inquiry asking a similar but slightly different question: whether all duplicates could be removed from a list, but not explicitly asking for solutions involving list comprehensions. The motivation for using list comprehensions specifically follows a recognition of their advantages over traditional for loops。用户建议使用 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
:
>>> import itertools
>>> [key for key, grp in itertools.groupby([1, 2, 2, 3])]
[1, 2, 3]
itertools.groupby
returns 一个迭代器。通过迭代它,你会得到一个密钥,组对。 (如果没有指定 key
函数,key
将是一个项目,否则 key
函数的 return 值)。 group
是一个迭代器,它将产生通过应用 key
函数分组的项目(如果未指定,相同的值将被分组)
>>> import itertools
>>> it = itertools.groupby([1, 2, 2, 3])
>>> it
<itertools.groupby object at 0x7feec0863048>
>>> for key, grp in it:
... print(key)
... print(grp)
...
1
<itertools._grouper object at 0x7feec0828ac8>
2
<itertools._grouper object at 0x7feec0828b00>
3
<itertools._grouper object at 0x7feec0828ac8>
>>> it = itertools.groupby([1, 2, 2, 3])
>>> for key, grp in it:
... print(list(grp))
...
[1]
[2, 2]
[3]
上面的解法,我只用了key
,因为这个问题不关心有多少项目是相邻的。
您可以将 list comprehension
and enumerate
与@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]
该列表理解 return 项(如果它是第一个)或者如果它不等于前一个则用于后续项。由于 if
语句的惰性评估,它会起作用。
您可以使用更简洁的循环解决方案:
>>> result = xs[:1]
>>> for e in xs:
if e != result[-1]:
result.append(e)
或者:
>>> result = []
>>> for e in xs:
if e not in result[-1:]:
result.append(e)
使用 itertools 方法中的成对使用(使用 zip_longest)可以让您轻松检查下一个元素:
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 的更冗长,所以这里有一个替代方案,使用 itertools
模块中的 zip_longest
:
>>> 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]