谷歌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)
只是为了展示另一种方式是另一个没有索引的单线版:
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部分将最后一个值放在结果中,因为只有结果才能结束.
像往常一样,我只是在这里宣传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)