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

Python切片可以用于按索引跳过一个特定元素吗?,python,Python,假设我正在编写一个递归函数,其中我希望将列表作为循环的一部分传递给缺少单个元素的函数。以下是一种可能的解决方案: def Foo(input): if len(input) == 0: return for j in input: t = input[:] t.remove(j) Foo(t) 有没有一种方法可以滥用slice操作符传递列表减去元素j,而不显式复制列表并从列表中删除项目?这是怎么回事 for i in range(len

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

def Foo(input):
    if len(input) == 0: return
    for j in input:
       t = input[:]
       t.remove(j)
       Foo(t)
有没有一种方法可以滥用slice操作符传递列表减去元素
j
,而不显式复制列表并从列表中删除项目?

这是怎么回事

for i in range(len(list_)):
    Foo(list_[:i] + list_[i+1:])
虽然在复制时忽略了索引
i
处的元素,但仍在复制项目


顺便说一句,您可以通过添加下划线来避免覆盖内置名称,如
列表

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

如果您的列表非常大,并且希望避免创建和删除列表实例的“搅动”,那么使用生成器如何

import itertools as it
def skip_i(seq, i):
    return it.chain(it.islice(seq, 0, i), it.islice(seq, i+1, None))
这将跳过第i个元素的工作推到了
itertools
的C语言中,因此这应该比用纯Python编写等价的代码要快

要在纯Python中实现这一点,我建议编写如下生成器:

def gen_skip_i(seq, i):
    for j, x in enumerate(seq):
        if i != j:
            yield x
编辑:这是我答案的一个改进版本,感谢下面评论中的@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))
这比我原来的答案有很大的改进。我最初的答案只适用于可索引的东西,比如列表,但这将适用于任何可索引的东西,包括迭代器!它从iterable生成一个显式迭代器,然后(在“链”中)提取第一个
i
值,在提取所有剩余值之前只跳过一个值


非常感谢@Blckknght

这里有一个与satoru的代码等价的代码,但速度更快,因为它在每次迭代中只复制一份列表,而不是两份:

before = []
after = list_[:]

for x in range(0, len(list_)):
    v = after.pop(0)
    Foo(before + after)
    before.append(v)

(在我的计算机上是11毫秒而不是18毫秒,对于使用
list(范围(1000))
生成的列表,您到底想做什么?也许有更好的方法来实现它?看到一个内置的名称被用作变量名,我会很害怕。请考虑使用<代码> LST 或<代码> L>代码>作为变量,而不是“遮蔽”<代码>列表>代码> BuiTin。但在这个问题上,我只是试图避免不必要地创建一个额外的变量。我还更正了代码中的错误。您是否正在尝试枚举输入的幂集?实际上,我正在尝试枚举两个集的所有可能配对。我不是在尝试提高效率,只是尝试避免使用额外的变量。此答案避免绑定额外的变量名。当然,它确实创建了一个额外的
list
实例。我刚刚用一个元素的输入列表测试了它,它正确地为我返回了空列表。看看代码,这正是我所期望的。请注意,只有将要跳过的索引正确指定为0(长度为1的列表的唯一有效索引)时,它才起作用。如果您在列表之外指定了一个索引,那么您就得到了整个列表,因此,当您测试它时,可能就是这样的情况?这个答案是正确的。我之前做了一些愚蠢的事情(忘记使用
enumerate
)。在这种情况下,我的输入很小,但如果我在更大的输入上尝试这个方法,我肯定会记住这个解决方案。通过对两个
islice
调用重用单个迭代器,可以进一步加快速度。第一个从
0
切到
i
,下一个从
1
切到
None
@Blckknght我不明白你的意思。也许你可以发布一个带有代码的答案,说明你的建议是如何运作的?我考虑制作一个迭代器,提取前N个项并生成它们,调用
next()
一次以提取并丢弃第I个项,然后生成所有剩余项。。。但是我想不出使用
itertools
技巧的方法,纯Python
for
循环比
itertools
中的C代码慢;返回it.chain(it.islice(迭代器,0,i),it.islice(迭代器,1,无))。好处是第二个
islice
只需要跳过一个值,而不是
i+1
。@Blckknght这太好了!谢谢你。答案已更新,感谢您的回答。
after.pop(0)
仍然有效地复制列表(尽管它可能比切片更有效,因为它不创建新对象,只是在内部移动引用)。列表除了在末尾之外,不会在任何地方进行添加或删除的优化。但是,它只需要复制列表的一部分,而不是全部(复杂性顺序相同,但在实践中速度更快)