显而易见的做法是先排序然后过滤,或者先过滤再排序。
如果你每次都有相同的列表,那么首先排序显然是一个胜利,因为你只需要排序一次而不是每次。这也意味着您可以使用二进制搜索而不是线性遍历进行过滤(如 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 行的东西,而不是最快或最可读……)。对于“一遍又一遍的相同列表”的情况,它几乎与二分法一样快,即使 没有 平分(当然你也可以使用 NumPy 平分)。