【问题标题】:Python, check if a number is in a range of many ranges in a list.Python,检查一个数字是否在列表中多个范围的范围内。
【发布时间】:2015-02-16 20:27:35
【问题描述】:

如果有这样的整数列表:

a_list = [2501, 2783, 3088, 3980, 465, 1001, 39392911, 39394382, 488955,489087, ......]
b_list = [474, 498, 47478821, 47479800, 3774, 8970, 484000, 486000......]

每2个数字表示一个自然数的范围,例如,a_list的范围是:

2501     2783      # 2501,2502,2503,2504,2505,2506,......,2783
3088     3980 
465      1001 
39392911 39394382 
488955   489087
......

对于给定的数字,搜索它所属的范围,并且优先级为a_list > b_list,即如果在a_list中找到范围,则停止搜索并继续搜索下一个数字。

我进行了大约 7 分钟的搜索约 50 个号码的测试。我有一个大数据集,可能需要以他的方式搜索 2000 万个数字。

如何编写代码以加快速度?

=============更多条件和信息=============

  • 每个列表中的数字可能超过 10,000 个。
  • 最多可搜索 3000 万个号码。
  • 列表的大小始终为 n * 2
  • a_list: [1st
  • 列表中的数字可能出现多次。
  • 优先级:a_list > b_list。

我的代码如下:

hasFound = 0

if hasFound == 0:
    for x, y in izip(*[iter(a_list)]*2):   # gives every 2 numbers
        if aNumber in range(x,y):
            a_list_counter +=1 
            hasFound = 1
            break

if hasFound == 0:       
    for x, y in izip(*[iter(b_list)]*2):
        if aNumber in range(x,y):
            b_list_counter += 1
            hasFound = 1
            break

提前非常感谢。

【问题讨论】:

  • 您使用的是蛮力方法。有一个更优雅的方法你没有想到。
  • if aNumber in range(x,y) 应该只是 x <= aNumber <= y
  • @Nsh 值得注意的是,这样做的原因是 Python 2.x 中的range(x, y) 实际上构建了一个所有数字的列表,这需要时间和内存。在 Python 3.x 中,range() 返回一个可以高效执行此类操作的特殊对象。
  • @Almo,你说得对,我想做得更好,但没能成功。
  • 我可能错了,但我的直觉告诉你,你想先对列表进行处理,然后将它们减少到尽可能小的范围集。就像 (1, 5) (3, 6) 会来 (1, 6)。

标签: python list search


【解决方案1】:

把它们都扔进一本大字典:

a_list = [2501, 2783, 3088, 3980, 465, 1001, 39392911, 39394382, 488955,489087, ......]
b_list = [474, 498, 47478821, 47479800, 3774, 8970, 484000, 486000......]
# into
ranges = {'a': [2501, 2783, 3088, 3980, 465, 1001, 39392911, 39394382, 488955,489087, ......],
          'b': [474, 498, 47478821, 47479800, 3774, 8970, 484000, 486000......]}

然后按顺序浏览每个列表,主要是按照您之前的方式:

numbers = [list of your target numbers]
scores = {} # dict to store results in

for number in numbers:

    for range_name in sorted(ranges):
        range_list = ranges[range_name]
        groups = zip(*[iter(range_list)] * 2)
        if any(start <= number < end for start,end in groups):
            scores.setdefault(range_name, 0) += 1

或者(我不确定这是否更快)你可以这样做:

for number in numbers:
    for range_name in sorted(ranges):
        range = ranges[range_name]
        if sorted(range + [number]).index(number) % 2:
            scores.setdefault(range, 0) += 1

在这种情况下,您将一个新数字放入已排序的列表中,重新排序(使用 TimSort 快速),并查看它是否介于两个现有数字之间。

【讨论】:

  • 这部分:scores.setdefault(range_name, 0) += 1 给出错误:SyntaxError: 无法分配给函数调用,defaultdict(list) 可以吗?我没有理解 += 1 的含义。还有sorted(ranges),因为搜索基于优先级,对吧?
  • 您是在使用scores = {} 还是使用默认字典?不,defaultdict(list) 不起作用,因为我们没有建立列表......
  • 嗨,我修复了错误,我使用分数作为字典。我用 1000、10000 个数字测试了你的 2 种方法,并打印了微秒,我的代码比你的第一种方法略快,比第二种方法快得多。但是,感谢您提供的帮助。
  • @Xiangwu “我用分数作为字典”这不正是我的第一种方法吗?是的,第二种方法要慢得多,这并不令我感到惊讶——list.index 相当慢。
  • 对不起,我可能让你感到困惑。对于您回答中的两种方法,我都尝试过。第一种方法出现错误。 “我用分数作为字典”只是为了回答你的最后一个问题。现在,我想如果我可以在并行/多处理中做到这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-05
  • 1970-01-01
  • 2018-10-21
  • 1970-01-01
  • 1970-01-01
  • 2022-06-10
相关资源
最近更新 更多