如果你想同时保留两者并且你可以使用一个函数,你可以使用:
def partition_on_index(it, indices):
indices = set(indices) # convert to set for fast lookups
l1, l2 = [], []
l_append = (l1.append, l2.append)
for idx, element in enumerate(it):
l_append[idx in indices](element)
return l1, l2
这里有一个技巧,那就是l_append[idx in indices]。 idx in indices 将返回一个布尔值,表示条件是True 还是False。由于布尔值是 Python 中整数的子类,因此可以将其解释为 0(如果是 False)或 1(如果是 True),因此是 l_append 元组的有效索引。
l_append 元组因此可以方便地替代循环内的if ... else ... 和它hoists 查找append 方法,从而提高函数的速度少量。所以这相当于:
def partition_on_index_probably_slower(it, indices):
indices = set(indices) # convert to set for fast lookups
l1, l2 = [], []
for idx, element in enumerate(it):
if idx in indices:
l2.append(element)
else:
l1.append(element)
return l1, l2
但是让我们看一个例子,第一个函数是如何工作的:
>>> idx = [1,4,5]
>>> mylist = ['a','b','c','d','e','f']
>>> l1, l2 = partition_on_index(mylist, idx)
>>> l1
['a', 'c', 'd']
>>> l2
['b', 'e', 'f']
时间安排:
我使用来自this answer 的框架来衡量性能:
import random
import numpy as np
def func1(mylist, idx):
idx = set(idx)
in_idx, not_in_idx = [], []
for i, e in enumerate(mylist):
(not_in_idx, in_idx)[i in idx].append(e)
return in_idx, not_in_idx
def partition_on_index(it, indices):
indices = set(indices) # convert to set for fast lookups
l1, l2 = [], []
l_append = (l1.append, l2.append)
for idx, element in enumerate(it):
l_append[idx in indices](element)
return l1, l2
def func2(mylist, idx):
x = np.asarray(mylist)
mask = np.ones(len(mylist), dtype=bool)
mask[idx] = False
return x[mask], x[~mask]
# Timing setup
timings = {func1: [], partition_on_index: [], func2: []}
sizes = [2**i for i in range(1, 20, 2)]
# Timing
for size in sizes:
mylist = list(range(size))
indices = list({random.randint(0, size-1) for _ in range(size//2)})
for func in timings:
res = %timeit -o func(mylist, indices)
timings[func].append(res)
所以对于小列表,函数partition_on_index 表现最好。但是,如果输入包含数千个(或更多)项,您可能会使用 Dmitri Chubarov 的 NumPy 方法获得更快的结果。然而,所有方法的性能都渐近相同,性能仅相差 2-5 倍。