快速比较数字是否在python中的范围列表中的方法

时间:2014-03-06 06:00:39

标签: python list data-structures compare range

我需要将数字列表与范围列表进行比较,看看数字是否在任何范围内。

示例:

list1 = [23,100,1,50,60,73]
list2 = [[0-10],[25-35],[100-110],[75-85]]

所以我需要迭代list1并将此数字与范围列表进行比较,看看这个数字是否落在任何范围内,如果是,我将增加该范围的计数器。

两个列表都非常大(100k到几百万或更多),而且数字是随机的。

那么处理这个问题的最佳方法是什么?

编辑 - 列表的格式可以是[低,高,计数器]的列表。上面的例子是数据样本,它并不真正遵循Python代码语法。两个名单都将是巨大的。

这个数字也是int。

感谢。

1 个答案:

答案 0 :(得分:2)

一种简单的方法是将第二个列表以元组(或两个元素列表)的形式存在,然后使用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]

timeit给出:

100000 loops, best of 3: 4.17 us per loop

现在,我假设你的范围是包容性的,就是里面有85和25这样的数字。如果list1中的数字是整数,list2是静态的(并且也只包含整数,加上范围非重叠),请将其展平,排序并移位边界为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

这个解决方案可能不适合您,因为如果您的第二个列表确实很大,它甚至可能不适合内存。