切片Python中的浮点值列表

时间:2014-11-19 22:01:51

标签: python list python-2.7 slice clamp

我有一个数千个花车的列表,我希望能够按最小和最大值进行切片。

E.G。使用:

flist = [1.9842, 9.8713, 5.4325, 7.6855, 2.3493, 3.3333]

(我的实际列表是400,000个浮点数,但上面是一个工作示例)

我想要像

这样的东西
def listclamp(minn, maxn, nlist):

这样

print listclamp(3, 8, flist)

应该给我

[3.3333, 5.4325, 7.6855]

我还需要做10,000至30,000次,所以速度确实很重要。

(到目前为止我没有尝试过代码,因为这对我来说是新的python领域)

3 个答案:

答案 0 :(得分:4)

显而易见的事情是排序然后过滤,或过滤然后排序。

如果每次都有相同的列表,首先排序显然是一个胜利,因为那时你只需要排序一次而不是每次排序。这也意味着您可以使用二进制搜索进行过滤而不是线性遍历(如ventsyv's answer中所述 - 尽管除非您的列表比此列表长得多,否则可能无法获得回报。

如果每次都有不同的列表,首先过滤可能是一个胜利,因为排序可能是一个缓慢的部分,而你正在那样排序一个较小的列表。

但是让我们停止推测并开始测试。

使用数千个浮点数的列表,其中大约一半在范围内:

In [1591]: flist = [random.random()*10 for _ in range(5000)]
In [1592]: %timeit sorted(x for x in flist if 3 <= x < 8)
100 loops, best of 3: 3.12 ms per loop
In [1593]: %timeit [x for x in sorted(flist) if 3 <= x < 8]
100 loops, best of 3: 4 ms per loop
In [1594]: %timeit l=sorted(flist); l[bisect.bisect_left(l, 3):bisect.bisect_right(l, 8)]
100 loops, best of 3: 3.36 ms per loop

所以,过滤然后排序获胜; ventsyn的算法确实弥补了部分差异,但并非全部。但是当然,如​​果我们只有一个列表进行排序,那么将其排序一次而不是数千次是明显的胜利:

In [1596]: l = sorted(flist)
In [1597]: %timeit l[bisect.bisect_left(l, 3):bisect.bisect_right(l, 8)]
10000 loops, best of 3: 29.2 µs per loop

所以,如果你反复使用相同的列表,显然要对它进行一次排序。

否则,您可以测试您的真实数据......但我们正在谈论削减高达22%的收费,这需要几毫秒。即使你做了成千上万次,也能节省你一秒钟。只需输入不同实现的成本 - 更不了解它们,概括它们,调试它们以及对它们进行性能测试 - 不仅如此。


但实际上,如果您在数十万个值上进行了数百万次操作,并且速度很重要,那么您首先应该不使用列表,而应该使用NumPy阵列。 NumPy只能存储原始float值,而不会将它们作为Python对象加载。除了节省内存(并改善缓存局部性),这意味着,np.sort中的内部循环比sorted中的内部循环更快,因为它不必进行Python函数调用这最终涉及拆箱两个数字,它只需要直接进行比较。

假设您首先将值存储在数组中,它是如何叠加的?

In [1607]: flist = np.random.random(5000) * 10
In [1608]: %timeit a = np.sort(flist); a = a[3 <= a]; a = a[a < 8]
1000 loops, best of 3: 742 µs per loop
In [1611]: %timeit c = b[3 <= b]; d = c[c < 8]
10000 loops, best of 3: 29.8 µs per loop

所以,它比“不同列表”情况下的过滤和排序快4倍,即使使用笨重的算法(我正在寻找可以塞进%timeit行的东西,而不是最快的或者最可读的...)。对于“一遍又一遍的相同列表”的情况,它几乎与bisect解决方案一样快,即使没有二等分(但当然你也可以与NumPy一样)。

答案 1 :(得分:1)

对列表进行排序(如果反复使用相同的列表,只对其进行一次排序),然后使用二进制搜索来查找下限和上限的位置。 想一想,有一个包可以做 - bisect。

答案 2 :(得分:0)

这将返回您想要的排序列表:

flist = [1.9842, 9.8713, 5.4325, 7.6855, 2.3493, 3.3333]

def listclamp(minn, maxn, nlist): 
    return sorted(filter(lambda x: xminn <= x <= maxn, nlist))

print listclamp(3, 8, flist) 

更快方法,使用list comprehensions

def listclamp2(minn, maxn, nlist): 
    return sorted([x for x in flist if (minn <= and x<=maxn)])

print listclamp2(3, 8, flist)

请注意,根据您的数据,最好先过滤列表然后对其进行排序(就像我在上面的代码中所做的那样)。

有关效果的更多信息,请参阅this link