我需要将数字列表与范围列表进行比较,看看该数字是否在任何范围内。
例:
list1 = [23,100,1,50,60,73]
list2 = [[0-10],[25-35],[100-110],[75-85]]
所以我需要迭代 list1 并将这个数字与范围列表进行比较,看看这个数字是否落在任何范围内,如果是,我将增加该范围的计数器。
这两个列表都将非常大(100K到数百万或更多),并且数量是随机的。
那么处理这个问题的最佳方法是什么?
编辑 - 列表的格式可以是列表,如[低,高,计数器]。上面的例子是数据示例,它并没有真正遵循 Python 代码语法。这两个列表都将是巨大的。
数字也是整数。
谢谢。
一个简单的方法是以元组(或双元素列表)的形式获得第二个列表,然后使用any
:
list1 = [23,100,1,50,60,73]
list2 = [(0,10), (25,35), (100,110), (75,85)]
[any(y[0] <= x <= y[1] for y in list2) for x in list1]
时间它给出:
100000 loops, best of 3: 4.17 us per loop
现在,我假设您的范围是包含的,即 85 和 25 这样的数字在里面。如果list1
中的数字是整数,而list2
是静态的(并且也只包含 int,加上范围不重叠),将其展平、排序并将边框移 0.5 以摆脱边框大小写,那么您可以使用非常有效的bisect
O(log(N)) 算法:
list2 = [(0,10),(25,35),(100,110),(75,85)]
list2 = [x for tup in list2 for x in tup]
list2.sort()
list2 = [l - 0.5 + i%2 for i,l in enumerate(list2)]
timeit [bisect_left(list2, x)%2 == 1 for x in list1]
100000 loops, best of 3: 1.64 us per loop
这是一个不太易读的设计,因为你有一堆数字,没有明显的指示左边框在哪里是右边框,但它要快得多,更具可扩展性。在这里,如果来自list1
的数字进入具有偶数索引的地方,则它在范围之间,否则,它在里面。
它仍然比简单地将所有数字存储在集合中并使用in
慢(仅当您list1
中的数字都int
时,这才有效):
list3 = set(range(0,11) + range(25,36) + range(100,111) + range(75,86))
[x in list3 for x in list1]
这给了:
1000000 loops, best of 3: 376 ns per loop
此解决方案可能对您来说不可行,因为如果您的第二个列表确实很大,它甚至可能不适合内存。