Google Python类|列表练习 -
给出一个数字列表,返回一个列表 所有相邻的==元素都被缩减为单个元素, 所以[1,2,3,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
这个问题甚至暗示可以通过修改传入的列表来完成。但是,python文档警告不要在使用for循环迭代列表时修改元素。
我想知道除了迭代列表之外我还能尝试什么,以完成这项工作。我不是在寻找解决方案,但也许是一个可以带我走向正确方向的提示。
更新
通过建议的改进更新上述代码。
使用建议的提示 -
使用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
答案 0 :(得分:17)
这是传统方式,在向后遍历列表时,原位删除相邻的重复项:
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]
>>>
更新:如果你想要一个生成器,但是(没有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]
>>>
更新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]
>>>
...或与itertools.imap
和/或operators.itemgetter
相关,如另一个答案所示。
object
个实例的预期行为是,它们中的任何一个都不等于任何类的任何其他实例,包括object
本身。因此,它们作为哨兵非常有用。
>>> object() == object()
False
值得注意的是itertools.groupby
object()
使用self.tgtkey = self.currkey = self.currvalue = object()
作为哨兵:
>>> 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>]
并且该代码在您运行它时会做正确的事情:
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
更新3:关于前向索引原位操作的备注
OP的修订代码:
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
最好写成:
{{1}}
答案 1 :(得分:9)
使用生成器迭代列表中的元素,yield
只有在更改时才会使用新的
itertools.groupby
就是这样做的。
如果迭代副本,则可以修改传入列表:
for elt in theList[ : ]:
...
答案 2 :(得分:6)
这里再展示一个没有索引的单线版:
def remove_adjacent(nums):
return [a for a,b in zip(nums, nums[1:]+[not nums[-1]]) if a != b]
not part将最后一个值放在结果中,因为只有结果才能结束。
答案 3 :(得分:5)
像往常一样,我只是在这里宣传Python itertools文档中令人印象深刻的recipes。
您要找的是函数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]
答案 4 :(得分:3)
嗯,katrielalex对itertools
是正确的,但OP在学习操纵内置数据结构的基础知识时似乎更感兴趣(或者应该是!)。至于操作列表,它确实需要思考,但我的建议是阅读this section of the documentation并尝试一些列表方法(提示:list.pop(),list.remove(),并学习一切关于切片。)
顺便说一句,发布的代码可以简化(但是你应该添加错误条件的处理):
def remove_adjacent(nums):
a = nums[:1]
for item in nums[1:]:
if item != a[-1]:
a.append(item)
return a
答案 5 :(得分:1)
您可以使用列表理解。例如,像这样的事情应该做的工作:
def remove_adjacent(L):
return [elem for i, elem in enumerate(L) if i == 0 or L[i-1] != elem]
或:
def remove_adjacent(L):
return [L[i] for i in xrange(len(L)) if i == 0 or L[i-1] != L[i]]
答案 6 :(得分:1)
来自Google的非常优雅的解决方案(来源:https://developers.google.com/edu/python/exercises/basic):
def remove_adjacent(nums):
result = []
for num in nums:
if len(result) == 0 or num != result[-1]:
result.append(num)
return result
答案 7 :(得分:1)
itertools.groupby
优越,但也有
reduce(lambda x, y: x + [y] if x[-1] != y else x, seq[1:], seq[0:1])
e.g。
>>> seq = [[1,1], [2,2], [3,3], [3,3], [2,2], [2,2], [1,1]]
>>> print reduce(lambda x, y: x + [y] if x[-1] != y else x, seq[1:], seq[0:1])
[[1, 1], [2, 2], [3, 3], [2, 2], [1, 1]]
当来自功能语言时,使用fold
完成此类操作时,使用reduce
通常会感觉很自然。
答案 8 :(得分:1)
试试这个:
def remove_adjacent(nums):
result = []
if len(nums) > 0:
result = [nums[0]]
for i in range(len(nums)-1):
if nums[i] != nums[i+1]:
result.append(nums[i+1])
return result
答案 9 :(得分:0)
如果您明确使用索引,可以修改您正在迭代的列表:
def remove_adjacent(l):
if len(l)<2:
return l
prev,i = l[0],1
while i < len(l):
if l[i] == prev:
del l[i]
else:
prev = l[i]
i += 1
它不适用于迭代器,因为迭代器在删除任意元素时不“知道”如何修改索引,因此更容易禁止它。某些语言的迭代器具有删除“当前项”的功能。
答案 10 :(得分:0)
nums = [1,1,1,2,2,3,3,3,5,5,1,1,1]
def remove_adjacent(nums):
"""Removes adjacent items by modifying "nums" in-place. Returns None!"""
i = 0
while True:
try:
if nums[i] == nums[i+1]:
# Letting you figure this part out,
# as it's a homework question
except IndexError:
break
print nums
remove_adjacent(nums)
print nums
编辑:pastebin of one way to do it here,万一你遇到困难并想知道..
答案 11 :(得分:0)
def remove_adjacent(nums):
newList=[]
for num in nums:
if num not in newList:
newList.append(num)
newList.sort()
return newList
答案 12 :(得分:0)
另一种方法。欢迎评论。
def remove_adjacent(nums):
'''modifies the list passed in'''
l, r = 0, 1
while r < len(nums):
if nums[l] == nums[r]:
r += 1
else:
l += 1
nums[l] = nums[r]
r += 1
del nums[l+1:]
答案 13 :(得分:0)
看到谷歌编写的代码是一件令人羞愧的事。这就是我想出的:
def remove_adjacent(nums):
rmvelement = []
checkedIndex = []
for num in nums:
if nums.index(num) not in checkedIndex:
index = nums.index(num)
checkedIndex.append(index)
skip = False
else:
skip = True
if skip == False:
for x in nums[index+1:]:
if x == num:
rmvelement.append(x)
else:
break
[nums.remove(_) for _ in rmvelement]
return nums
答案 14 :(得分:0)
这应该适用于透明(尽管是迂回)的解决方案:
def remove_adjacent(nums):
numstail = [i for i in range(0,len(nums))]
nums = nums + numstail
for i in nums:
if nums[i] == nums[i-1]:
del nums[i]
return nums[:-len(numstail)]
逻辑如下:
len(numtails)
索引位置。(numstail
被定义为避免索引超出任何长度列表的范围)
答案 15 :(得分:0)
def removeDupAdj2(a):
b=[]
for i in reversed(range(1,len(a))):
if(a[i-1] == a[i]):
del(a[i])
#print(a)
return a
a = [int(i) for i in '1 2 3 3 4 4 3 5 4 4 6 6 6 7 8 8 8 9 1 1 0 0'.split(' ')]
a
res = removeDupAdj2(a)
res
答案 16 :(得分:-3)
由于你是Python课程,我猜你是语言新手。因此,对于您和其他任何初学者,我编写了一个简单的代码版本,以帮助其他人了解逻辑。
original= [1, 2, 2, 3]
newlist=[]
for item in original:
if item in newlist:
print "You don't need to add "+str(item)+" again."
else:
newlist.append(item)
print "Added "+str(item)
print newlist