可以使用Python切片来按索引跳过一个特定元素吗?

mer*_*011 5 python

假设我正在编写一个递归函数,希望将a传递list给缺少单个元素的函数,作为循环的一部分。这是一种可能的解决方案:

def Foo(input):
    if len(input) == 0: return
    for j in input:
       t = input[:]
       t.remove(j)
       Foo(t)
Run Code Online (Sandbox Code Playgroud)

有没有一种方法可以滥用slice运算符来传递列表减去元素,j而无需显式复制列表并从中删除项目?

sat*_*oru 5

那这个呢?

for i in range(len(list_)):
    Foo(list_[:i] + list_[i+1:])
Run Code Online (Sandbox Code Playgroud)

您仍在复制项目,尽管您i在复制时忽略了索引处的元素。

顺便说一句,您总是可以尝试避免覆盖内置名称,例如list附加下划线。


ste*_*eha 5

如果您的列表很小,我建议使用@satoru 的答案中的方法。

如果您的列表非常大,并且您想避免创建和删除列表实例的“混乱”,那么使用生成器怎么样?

import itertools as it
def skip_i(seq, i):
    return it.chain(it.islice(seq, 0, i), it.islice(seq, i+1, None))
Run Code Online (Sandbox Code Playgroud)

这将跳过第 i 个元素的工作推入了 C 的内部itertools,因此这应该比用纯 Python 编写等效内容更快。

要在纯 Python 中完成此操作,我建议编写一个如下所示的生成器:

def gen_skip_i(seq, i):
    for j, x in enumerate(seq):
        if i != j:
            yield x
Run Code Online (Sandbox Code Playgroud)

编辑:这是我的答案的改进版本,感谢下面评论中的@Blckknght。

import itertools as it
def skip_i(iterable, i):
    itr = iter(iterable)
    return it.chain(it.islice(itr, 0, i), it.islice(itr, 1, None))
Run Code Online (Sandbox Code Playgroud)

这比我原来的答案有很大的进步。我原来的答案只适用于可索引的东西,例如列表,但这对于任何可迭代的东西都可以正常工作,包括迭代器!它从可迭代对象中创建一个显式迭代器,然后(在“链”中)提取第一个i值,并在提取所有剩余值之前仅跳过一个值。

非常感谢@Blckknght!

  • 这只是您的代码的一个微小变化:`iterator=iter(seq); 返回 it.chain(it.islice(iterator, 0, i), it.islice(iterator, 1, None))`。好处是第二个“islice”只需要跳过一个值,而不是其中的“i+1”。 (2认同)