我想知道是否有一个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
?“
或者,“最多 pythonic 处理这个问题的方法是什么?”
附录:
说我必须对可变大小的数千个列表(实际上是粒子的轨迹)进行这种子采样操作(即可变时间长度的轨迹)。所以我无法预先计算出正确的索引集。
答案 0 :(得分:2)
您必须生成索引,然后使用列表推导来选择与这些索引不匹配的所有值。使用range()
对象来测试索引的有效方法(在python 2中xrange()
):
indices = range(offset, len(a), step)
[v for i, v in enumerate(a) if i not in indices]
Python 3中的range()
对象(Python 2中的xrange()
)仅保存起始值,结束值和步长值,如果测试值为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)):
答案 1 :(得分: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 :(得分:0)
在使用if的同时,以下是单步列表理解,我相信为您提供所需的答案:
>>> 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更有效率。