从列表中删除相邻的重复元素

Vai*_*pai 15 python

谷歌Python类| 清单练习 -

给定一个数字列表,返回一个列表,其中所有相邻的==元素已减少为单个元素,因此[1,2,2,3]返回[1,2,3].您可以创建新列表或修改传入列表.

我使用新列表的解决方案是 -

def remove_adjacent(nums):
  a = []
  for item in nums:
    if len(a):
      if a[-1] != item:
        a.append(item)
    else: a.append(item)        
  return a
Run Code Online (Sandbox Code Playgroud)

这个问题甚至暗示可以通过修改传入的列表来完成.但是,python文档警告不要在使用for循环迭代列表时修改元素.

我想知道除了迭代列表之外我还能尝试什么,以完成这项工作.我不是在寻找解决方案,但也许是一个可以带我走向正确方向的提示.

UPDATE

使用建议的改进更新了上述代码.

使用建议的提示使用while循环执行以下操作 -

def remove_adjacent(nums):
  i = 1
  while i < len(nums):    
    if nums[i] == nums[i-1]:
      nums.pop(i)
      i -= 1  
    i += 1
  return nums
Run Code Online (Sandbox Code Playgroud)

Joh*_*hin 19

这是传统的方法,在向后遍历列表时,原位删除相邻的重复项:

Python 1.5.2 (#0, Apr 13 1999, 10:51:12) [MSC 32 bit (Intel)] on win32
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>> def dedupe_adjacent(alist):
...     for i in xrange(len(alist) - 1, 0, -1):
...         if alist[i] == alist[i-1]:
...             del alist[i]
...
>>> data = [1,2,2,3,2,2,4]; dedupe_adjacent(data); print data
[1, 2, 3, 2, 4]
>>> data = []; dedupe_adjacent(data); print data
[]
>>> data = [2]; dedupe_adjacent(data); print data
[2]
>>> data = [2,2]; dedupe_adjacent(data); print data
[2]
>>> data = [2,3]; dedupe_adjacent(data); print data
[2, 3]
>>> data = [2,2,2,2,2]; dedupe_adjacent(data); print data
[2]
>>>
Run Code Online (Sandbox Code Playgroud)

更新:如果你想要一个生成器但是(没有itertools.groupby或者(你可以输入比你能阅读它的文档更快的速度并了解它的默认行为)),这里有一个六线工作:

Python 2.3.5 (#62, Feb  8 2005, 16:23:02) [MSC v.1200 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> def dedupe_adjacent(iterable):
...     prev = object()
...     for item in iterable:
...         if item != prev:
...             prev = item
...             yield item
...
>>> data = [1,2,2,3,2,2,4]; print list(dedupe_adjacent(data))
[1, 2, 3, 2, 4]
>>>
Run Code Online (Sandbox Code Playgroud)

更新2:关于巴洛克itertools.groupby()和极简主义object()......

要获得重复数据删除效果itertools.groupby(),你需要在其周围包含一个列表理解,以丢弃不需要的石斑鱼:

>>> [k for k, g in itertools.groupby([1,2,2,3,2,2,4])]
[1, 2, 3, 2, 4]
>>>
Run Code Online (Sandbox Code Playgroud)

...或者在另一个答案中看到的itertools.imap和/或operators.itemgetter其他问题.

object实例的预期行为是它们中没有一个比较等于任何类的任何其他实例,包括object它自己.因此,它们作为哨兵非常有用.

>>> object() == object()
False
Run Code Online (Sandbox Code Playgroud)

值得一提的是,Python的引用代码itertools.groupby用途object()定为定点:

self.tgtkey = self.currkey = self.currvalue = object()
Run Code Online (Sandbox Code Playgroud)

当你运行它时,该代码做正确的事情:

>>> data = [object(), object()]
>>> data
[<object object at 0x00BBF098>, <object object at 0x00BBF050>]
>>> [k for k, g in groupby(data)]
[<object object at 0x00BBF098>, <object object at 0x00BBF050>]
Run Code Online (Sandbox Code Playgroud)

更新3:关于前向指数原位操作的评论

OP的修订代码:

def remove_adjacent(nums):
  i = 1
  while i < len(nums):    
    if nums[i] == nums[i-1]:
      nums.pop(i)
      i -= 1  
    i += 1
  return nums
Run Code Online (Sandbox Code Playgroud)

写得更好:

def remove_adjacent(seq): # works on any sequence, not just on numbers
  i = 1
  n = len(seq)
  while i < n: # avoid calling len(seq) each time around
    if seq[i] == seq[i-1]:
      del seq[i]
      # value returned by seq.pop(i) is ignored; slower than del seq[i]
      n -= 1
    else:
      i += 1
  #### return seq #### don't do this
  # function acts in situ; should follow convention and return None
Run Code Online (Sandbox Code Playgroud)


Kat*_*iel 10

使用生成器迭代列表的元素,yield只有在更改时才重新生成.

itertools.groupby 就是这样.

如果迭代副本,则可以修改传入列表:

for elt in theList[ : ]:
    ...
Run Code Online (Sandbox Code Playgroud)


Ton*_*nen 6

只是为了展示另一种方式是另一个没有索引的单线版:

def remove_adjacent(nums):
     return [a for a,b in zip(nums, nums[1:]+[not nums[-1]]) if a != b]
Run Code Online (Sandbox Code Playgroud)

not部分将最后一个值放在结果中,因为只有结果才能结束.


Muh*_*uri 5

像往常一样,我只是在这里宣传Python itertools文档中令人印象深刻的食谱.

您正在寻找的是功能unique_justseen:

from itertools import imap, groupby
from operator import itemgetter

def unique_justseen(iterable, key=None):
    "List unique elements, preserving order. Remember only the element just seen."
    # unique_justseen('AAAABBBCCDAABBB') --> A B C D A B
    # unique_justseen('ABBCcAD', str.lower) --> A B C A D
    return imap(next, imap(itemgetter(1), groupby(iterable, key)))

list(unique_justseen([1,2,2,3])) # [1, 2, 3]
Run Code Online (Sandbox Code Playgroud)