2

我想知道是否有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方式是什么?”

附录:

假设我必须对数千个可变大小(即可变时间长度的轨迹)的列表(实际上是粒子的轨迹)进行此子采样操作。所以我无法预先计算正确的索引集。

4

3 回答 3

2

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

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

Python 3 中的range()对象(xrange()在 Python 2 中)仅包含 start、end 和 step 值,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)):
于 2013-10-08T09:08:01.220 回答
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
于 2013-10-08T13:39:08.210 回答
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 更有效。

于 2013-10-08T09:21:49.760 回答