更新:
more_itertools
库已经发布了
more_itertool.replace
,这是一个解决此特定问题的工具(参见选项3)。
首先,这里有一些适用于通用可迭代对象(列表、字符串、迭代器等)的其他选项:
代码
选项1 - 无需使用库:
def remove(iterable, subsequence):
"""Yield non-subsequence items; sans libraries."""
seq = tuple(iterable)
subsequence = tuple(subsequence)
n = len(subsequence)
skip = 0
for i, x in enumerate(seq):
slice_ = seq[i:i+n]
if not skip and (slice_ == subsequence):
skip = n
if skip:
skip -= 1
continue
yield x
选项2 - 使用more_itertools
库
import more_itertools as mit
def remove(iterable, subsequence):
"""Yield non-subsequence items."""
iterable = tuple(iterable)
subsequence = tuple(subsequence)
n = len(subsequence)
indices = set(mit.locate(mit.windowed(iterable, n), pred=lambda x: x == subsequence))
it_ = enumerate(iterable)
for i, x in it_:
if i in indices:
mit.consume(it_, n-1)
else:
yield x
演示
list(remove(big_list, sub_list))
# [2, 3, 4]
list(remove([1, 2, 1, 2], sub_list))
# []
list(remove([1, "a", int, 3, float, "a", int, 5], ["a", int]))
# [1, 3, float, 5]
list(remove("11111", "111"))
# ['1', '1']
list(remove(iter("11111"), iter("111")))
# ['1', '1']
第三种选择 - 使用 more_itertools.replace
:
演示
pred = lambda *args: args == tuple(sub_list)
list(mit.replace(big_list, pred=pred, substitutes=[], window_size=2))
pred=lambda *args: args == tuple(sub_list)
list(mit.replace([1, 2, 1, 2], pred=pred, substitutes=[], window_size=2))
pred=lambda *args: args == tuple(["a", int])
list(mit.replace([1, "a", int, 3, float, "a", int, 5], pred=pred, substitutes=[], window_size=2))
pred=lambda *args: args == tuple("111")
list(mit.replace("11111", pred=pred, substitutes=[], window_size=3))
pred=lambda *args: args == tuple(iter("111"))
list(mit.replace(iter("11111"), pred=pred, substitutes=[], window_size=3))
详情
在所有这些示例中,我们使用较小的窗口切片扫描主序列。我们产生未在切片中找到的任何内容,并跳过切片中的任何内容。
选项1-不使用库
迭代枚举序列并评估大小为n
(子序列的长度)的片段。如果即将到来的片段等于子序列,则重置skip
并生成该项。否则,迭代超过它。skip
跟踪要推进循环的次数,例如,sublist
的大小为n=2
,因此每次匹配时跳过两次。
请注意,您可以通过删除前两个元组分配并将iterable
参数替换为seq
来将此选项转换为仅使用sequences工作,例如:def remove(seq,subsequence):
。
选项2 - 使用more_itertools
对于可迭代对象中的每个匹配子序列,都会找到相应的索引。在枚举迭代器时,如果在indices
中找到了索引,则通过从迭代器中消耗下一个n-1
元素来跳过其余子序列。否则,将生成一个项目。
通过运行> pip install more_itertools
来安装此库。
选项3 - 使用more_itertools.replace
此工具使用谓词定义的子序列替换项目。为了删除项目,我们用空容器(例如substitutes=[]
)进行替换。被替换的项目的长度由window_size
参数指定(该值等于子序列的长度)。