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
技巧的方法,纯Pythonfor
循环比itertools
中的C代码慢;返回it.chain(it.islice(迭代器,0,i),it.islice(迭代器,1,无))。好处是第二个islice
只需要跳过一个值,而不是i+1
。@Blckknght这太好了!谢谢你。答案已更新,感谢您的回答。after.pop(0)
仍然有效地复制列表(尽管它可能比切片更有效,因为它不创建新对象,只是在内部移动引用)。列表除了在末尾之外,不会在任何地方进行添加或删除的优化。但是,它只需要复制列表的一部分,而不是全部(复杂性顺序相同,但在实践中速度更快)