Python切片能否按索引跳过一个特定元素?
假设我在写一个递归函数,我想在一个循环中把一个少了一个元素的list
传给这个函数。这里有一个可能的解决方案:
def Foo(input):
if len(input) == 0: return
for j in input:
t = input[:]
t.remove(j)
Foo(t)
有没有办法利用切片操作符,直接传递去掉元素j
的列表,而不需要显式地复制整个列表并把那个元素删掉呢?
3 个回答
1
这里有一段代码,它和satoru的代码功能一样,但运行得更快,因为它每次只复制一次列表,而不是复制两次:
before = []
after = list_[:]
for x in range(0, len(list_)):
v = after.pop(0)
Foo(before + after)
before.append(v)
(在我的电脑上,对于用list(range(1000))
生成的列表,这段代码的运行时间是11毫秒,而satoru的代码是18毫秒)
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))
这样做可以把跳过第i个元素的工作交给itertools
的底层代码来处理,所以这比用纯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))
这个改进比我最初的回答要好很多。我最初的回答只适用于可以索引的东西,比如列表,但这个方法对任何可迭代的对象都能正确工作,包括迭代器!它会从可迭代对象中明确创建一个迭代器,然后(以“链”的方式)提取前i
个值,之后只跳过一个值,然后提取所有剩下的值。
非常感谢@Blckknght!
7
这个怎么样?
for i in range(len(list_)):
Foo(list_[:i] + list_[i+1:])
你还是在复制东西,只不过在复制的时候忽略了索引为 i
的那个元素。
顺便说一下,你可以通过在内置名称后面加下划线来避免覆盖它们,比如 list
。