我有一个数千个花车的列表,我希望能够按最小和最大值进行切片。
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领域)
答案 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。