如何从列表中删除连续的重复项?

5
如何在Python中从类似于此的列表中删除连续重复项?
lst = [1,2,2,4,4,4,4,1,3,3,3,5,5,5,5,5]

有一个独特的列表或集合并不能解决问题,因为在之前的列表中存在一些重复的值,比如1,...,1。

我希望结果是这样的:

newlst = [1,2,4,1,3,5]

请您考虑以下情况:当我有一个类似于这样的列表 [4, 4, 4, 4, 2, 2, 3, 3, 3, 3, 3, 3], 并且我希望结果为[4,2,3,3]而不是[4,2,3]


7
“collapse” 的意思是什么? - neverendingqs
5
查看 itertools.groupby - MaxU - stand with Ukraine
你是在询问工具还是实现方法?如果你想自己编写,可以通过迭代并保留与前一个元素不匹配的任何元素来实现。 - Vivek Chavda
1
map(operator.itemgetter(0), itertools.groupby(lst)) - Ozgur Vatansever
@ozgur 他想要一个列表而不是生成器。如果他需要对数据进行两次传递,那么生成器将无法满足需求。 - Bharel
显示剩余6条评论
7个回答

13

itertools.groupby() 是您的解决方案。

newlst = [k for k, g in itertools.groupby(lst)]
如果您希望按照项目的值进行分组并限制每个组的大小,即8个4将变成[4,4],9个3将变成[3,3,3],这里有两个选项可以实现:
import itertools

def special_groupby(iterable):
    last_element = 0
    count = 0
    state = False
    def key_func(x):
        nonlocal last_element
        nonlocal count
        nonlocal state
        if last_element != x or x >= count:
            last_element = x
            count = 1
            state = not state
        else:
            count += 1
        return state
    return [next(g) for k, g in itertools.groupby(iterable, key=key_func)]

special_groupby(lst)

或者

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return itertools.zip_longest(*args, fillvalue=fillvalue)

newlst = list(itertools.chain.from_iterable(next(zip(*grouper(g, k))) for k, g in itertools.groupby(lst)))

选择您认为合适的方法。这两种方法都适用于大于0的数字。


它的功能非常好,但是对于像这样的列表 [4, 4, 4, 4, 2, 2, 3, 3, 3, 3, 3, 3],我希望结果是 [4,2,3,3] 而不是 [4,2,3]。你能指导我如何解决这个问题吗? - Elmahy
@ahmedmar 为什么会有 [4,2,3,3]?在这种情况下,[4,2,3] 是正确的输出。您想要删除重复项,而中间没有其他内容。 - Bharel
另一个例子,假设有一个列表 [2,2,2,2,3,3,3,3],如果我指定使用itertool来收集每两个重复项,那么我将得到[2,2,3,3]。 - Elmahy
是否有理由不直接使用 newlst = [item[0] for item in itertools.groupby(lst)] 呢? - Jacob Vlijm
@jacob 这不是他想要的结果。 - Bharel
显示剩余3条评论

3
list1 = ['a', 'a', 'a', 'b', 'b' , 'a', 'f', 'c', 'a','a']
temp_list = []


for item in list1:   
   if len(temp_list) == 0:
      temp_list.append(item)

   elif len(temp_list) > 0:
      if  temp_list[-1] != item:
          temp_list.append(item)

print(temp_list)
  1. 从主列表(list1)获取每个项目。
  2. 如果'temp_list'为空,则添加该项目。
  3. 否则,请检查temp_list中的最后一项是否与我们从'list1'获取的项不同。
  4. 如果项目不同,则将其附加到temp_list中。

2

如果您想使用@MaxU建议的itertools方法,可能的代码实现如下:

import itertools as it

lst=[1,2,2,4,4,4,4,1,3,3,3,5,5,5,5,5]

unique_lst = [i[0] for i in it.groupby(lst)]

print(unique_lst)

0

你可能想要这样的东西。

lst = [1, 1, 2, 2, 2, 2, 3, 3, 4, 1, 2]
prev_value = None
for number in lst[:]: # the : means we're slicing it, making a copy in other words
    if number == prev_value:
        lst.remove(number)
    else:
        prev_value = number

所以,我们正在遍历列表,如果它与前一个数字相同,则将其从列表中删除,否则,我们更新前一个数字。

可能有更简洁的方法,但这是我看起来最明显的方法。

希望对你有所帮助。


最好构建一个新列表,因为在for循环中从列表中删除项目可能会导致问题。 - joel goldstick
我们是这样做的。我们正在迭代列表的切片副本,而不是原始列表。因此,在我们进行迭代时删除元素不会导致出现错误。 - Craig Brett
我错过了..抱歉! - joel goldstick
没关系 - 它以前已经咬过我了 :) - Craig Brett
即使在副本上进行操作,如果重复的值在列表中出现了多次,这也不会正确工作。例如,在[3, 2, 3, 3]上尝试一下。问题在于list.remove(3)不会从末尾删除重复的3,而是从开头删除单个的3list.remove也非常慢(每次删除需要O(N)时间)。 - Blckknght
真的吗?为什么这样说? - Craig Brett

0
newlist=[]    
prev=lst[0]
newlist.append(prev)
    for each in lst[:1]: #to skip 1st lst[0]
        if(each!=prev):
            newlist.append(each)  
         prev=each             

1
虽然此代码可能回答了问题,但提供有关为什么和/或如何回答问题的附加上下文可以提高其长期价值。不鼓励仅包含代码的答案。 - Ajean

0
st = ['']
[st.append(a) for a in [1,2,2,4,4,4,4,1,3,3,3,5,5,5,5,5] if a != st[-1]]
print(st[1:])

虽然这段代码可能回答了问题,但是提供关于为什么和/或如何回答问题的额外上下文可以提高其长期价值。仅限代码的答案是不被鼓励的。 - Ajean

0

检查下一个元素是否始终不等于项目。如果是,则追加。

lst = [1,2,2,4,4,4,4,1,3,3,3,5,5,5,5,5]

new_item = lst[0]
new_list = [lst[0]]
for l in lst:
   if new_item != l:
     new_list.append(l)
     new_item = l

print new_list
print lst

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接