2013-10-08 25 views
2

我想知道是否有Python的“核心”语法来处理补充的基于范围的选择。Python - 基于范围的子列表选择的补充

都说

a = [0,1,2,3,4,5,6] 

然后,例如,因此

offset = 1 
step = 3 
a[offset::step] = [1,4]. 

我的问题是:

“我可以这样做

a[~(offset::step)] == [0,2,3,5,6] 

不使用ifs ?”

或者,“什么是最难以处理这个问题的方法?”

附录:

说,我所要做的数千名单这个子采样操作可变大小的(粒子的轨迹确实)(即可变时间长度的轨迹)。所以我不能预先计算正确的索引集。

回答

2

集(通常情况下)约一个数量级的速度更快,即使你不填充指数的时间提前:

r100 = range(100) 
r2 = range(3, 40, 3) 

# Find indices in r100 that aren't in r2. 
# This is a set difference (or symmetric difference) 
## Set methods 
# Precalculated is fastest: 
sr100 = set(r100) 
sr2 = set(r2) 
%timeit sr100 - sr2 
100000 loops, best of 3: 3.84 us per loop 

# Non-precalculated is still faster: 
%timeit set(range(100))^set(range(3,40,3)) 
100000 loops, best of 3: 9.76 us per loop 
%timeit set(xrange(100))^set(xrange(3,40,3)) 
100000 loops, best of 3: 8.84 us per loop 

# Precalculating the original indices still helps, if you can hold it in memory: 
%timeit sr100^set(xrange(3,40,3)) 
100000 loops, best of 3: 4.87 us per loop 

# This is true even including converting back to list, and sorting (if necessary): 
%timeit [x for x in sr100^set(xrange(3,40,3))] 
100000 loops, best of 3: 9.02 us per loop 
%timeit sorted(x for x in sr100^set(xrange(3,40,3))) 
100000 loops, best of 3: 15 us per loop 


## List comprehension: 

# Precalculated indices 
%timeit [x for x in r100 if x not in r2] 
10000 loops, best of 3: 30.5 us per loop 

# Non-precalculated indices, using xrange 
%timeit [x for x in xrange(100) if x not in xrange(3, 40, 3)] 
10000 loops, best of 3: 65.8 us per loop 

# The cost appears to be in the second xrange? 
%timeit [x for x in r100 if x not in xrange(3, 40, 3)] 
10000 loops, best of 3: 64.3 us per loop 
%timeit [x for x in xrange(100) if x not in r2] 
10000 loops, best of 3: 29.9 us per loop 
# xrange is not really any faster than range here - uses less memory, but still have 
# to walk through entire list 
%timeit [x for x in range(100) if x not in range(3, 40, 3)] 
10000 loops, best of 3: 63.5 us per loop 
2

您必须生成索引,然后使用列表理解选择与这些索引不匹配的所有值。 (在python 2 xrange())使用range()对象为一种有效的方法来测试指标:

indices = range(offset, len(a), step) 
[v for i, v in enumerate(a) if i not in indices] 

range()对象在Python 3(xrange()在Python 2)仅保持开始,结束,和步长值,in如果测试值是范围的一部分,测试只需快速计算。

演示:

>>> a = [0, 1, 2, 3, 4, 5, 6] 
>>> offset, step = 1, 3 
>>> indices = range(offset, len(a), step) 
>>> indices 
range(1, 7, 3) 
>>> [v for i, v in enumerate(a) if i not in indices] 
[0, 2, 3, 5, 6] 

是的,这仍然需要使用if语句,但该测试是便宜的,并可根据需要在发电机表达式被合并:当仍然使用

for i in (v for i, v in enumerate(a) if i not in range(offset, len(a), step)): 
+0

我看,所以通过'xrange'我不是计算整个索引组。这被认为更快。 – Acorbe

+0

@Acorbe:'xrange()'会员测试的成本不变,是的。 –

0

如果,下面是一个单步列表理解,我相信给你所需的答案:

>>> offset = 1 
>>> step = 3 
>>> a = [0,1,2,3,4,5,6] 
>>> [v for i, v in enumerate(a) if not i%step == offset] 
[0, 2, 3, 5, 6] 
>>> 

我不知道的是,如果这比使用范围构造优于mod更有效。