从列表中删除相邻的重复组,同时保留顺序
Remove groups of adjacent duplicates from list while preserving order
有很多类似的问题(比如this one),但我没有找到适合我的问题。
我的 objective 是从列表中删除 组相邻的重复项。
例如,如果我的列表是
['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'A', 'C', 'C']
我想要的输出是
['A', 'B', 'C', 'A', 'C']
即每组相邻的重复项都被删除,只保留其中一个。
到目前为止,我的代码涉及一个 for 循环,条件为:
def reduce_duplicates(l):
assert len(l) > 0, "Passed list is empty."
result = [l[0]] # initialization
for i in l:
if i != result[-1]:
result.append(i)
return result
l = ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'A', 'C', 'C']
print(reduce_duplicates(l))
# ['A', 'B', 'C', 'A', 'C']
它产生了预期的输出,但我认为有一种本机的、优化的和优雅的方法可以达到相同的结果。是真的吗?
使用 itertools
中的 groupby
:
lst = ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'A', 'C', 'C']
out = [k for k, _ in groupby(lst)]
print(out)
# Output
['A', 'B', 'C', 'A', 'C']
更新
您还可以使用 itertools
中的 zip_longest
:
lst = ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'A', 'C', 'C']
out = [l for l, r in zip_longest(lst, lst[1:]) if l != r]
print(out)
# Output
['A', 'B', 'C', 'A', 'C']
或没有任何导入:
lst = ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'A', 'C', 'C']
out = [lst[0]] + [r for l, r in zip(lst, lst[1:]) if l != r]
print(out)
# Output
['A', 'B', 'C', 'A', 'C']
itertools 文档为此提供了 recipe unique_justseen
。由于它使用地图,它可能比常规列表理解快一点,并且还支持 key-function.
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 map(next, map(operator.itemgetter(1), groupby(iterable, key)))
有很多类似的问题(比如this one),但我没有找到适合我的问题。
我的 objective 是从列表中删除 组相邻的重复项。
例如,如果我的列表是
['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'A', 'C', 'C']
我想要的输出是
['A', 'B', 'C', 'A', 'C']
即每组相邻的重复项都被删除,只保留其中一个。
到目前为止,我的代码涉及一个 for 循环,条件为:
def reduce_duplicates(l):
assert len(l) > 0, "Passed list is empty."
result = [l[0]] # initialization
for i in l:
if i != result[-1]:
result.append(i)
return result
l = ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'A', 'C', 'C']
print(reduce_duplicates(l))
# ['A', 'B', 'C', 'A', 'C']
它产生了预期的输出,但我认为有一种本机的、优化的和优雅的方法可以达到相同的结果。是真的吗?
使用 itertools
中的 groupby
:
lst = ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'A', 'C', 'C']
out = [k for k, _ in groupby(lst)]
print(out)
# Output
['A', 'B', 'C', 'A', 'C']
更新
您还可以使用 itertools
中的 zip_longest
:
lst = ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'A', 'C', 'C']
out = [l for l, r in zip_longest(lst, lst[1:]) if l != r]
print(out)
# Output
['A', 'B', 'C', 'A', 'C']
或没有任何导入:
lst = ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'A', 'C', 'C']
out = [lst[0]] + [r for l, r in zip(lst, lst[1:]) if l != r]
print(out)
# Output
['A', 'B', 'C', 'A', 'C']
itertools 文档为此提供了 recipe unique_justseen
。由于它使用地图,它可能比常规列表理解快一点,并且还支持 key-function.
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 map(next, map(operator.itemgetter(1), groupby(iterable, key)))