dongyanpai2701 2016-09-28 13:07
浏览 64
已采纳

在Golang的整数范围地图中查找

The problem I want to resolve can be expressed this way: I want to lookup an Integer in a hashmap of integer ranges.

0-4: dog,
5-8: cat,
9-18: bird,
19-21: dog,
22-22: bird,
...

Where:

lookup(3) -> dog
lookup(10) -> bird

However, thinking of this problem as a hashmap is probably not the right way to go. I'm working with ~ 140,000 ranges, which belong to one of ~ 200 possible classes.

Any idea of how to do this in Golang ? Or which track to follow to reach a reasonable solution (~O(log(n) ?) ? A way to describe this problem more generically ?

Thanks for your help !

  • 写回答

2条回答 默认 最新

  • dongtang1910 2016-09-28 13:22
    关注

    If ranges are disjunct (that is a concrete number can only belong to one range), you can find a range using a binary search. This is O(log(n)) complexity.

    If ranges are contiguous, it is also enough to "model" a range using only one number, either with its start or its end. This also applies in your case.

    We can list the range boundaries in an int slice in ascendent order, and we can perform a binary search in this sorted slice. We model ranges with their maximum value since the sequence of ranges is without any holes. This will give us the index of the range. We can store the names in a separate slice, and return the name at the index we just found as the result of binary search.

    Here's the surprisingly short implementation, a one-line function:

    var ranges = []int{-1, 4, 8, 18, 21, 22}
    var names = []string{"", "dog", "cat", "bird", "dog", "bird", ""}
    
    func getName(n int) string {
        return names[sort.SearchInts(ranges, n)]
    }
    

    Testing it:

    nums := []int{-1, 3, 6, 10, 20, 22, 100}
    for _, n := range nums {
        if name := getName(n); name == "" {
            fmt.Printf("Invalid number: %4d
    ", n)
        } else {
            fmt.Printf("Number        : %4d, Name: %s
    ", n, name)
        }
    }
    

    Output (try it on the Go Playground):

    Invalid number:   -1
    Number        :    3, Name: dog
    Number        :    6, Name: cat
    Number        :   10, Name: bird
    Number        :   20, Name: dog
    Number        :   22, Name: bird
    Invalid number:  100
    

    Note: this solution is also used in a similar question on the Code Review StackExchange site: Classifying by age

    Handling non-contiguous ranges

    If ranges would not cover every number (meaning there are "holes" between ranges), then you may easily handle that by adding the holes as "virtual" ranges, and give them the empty string "" name (which we used for invalid ranges). That's all.

    For example, let's modify your original problem to this:

    0-4: dog,
    5-8: cat,
    9-15: bird,
    19-21: dog,
    22-22: bird,
    

    As you can see, there is a "hole" between 9-15: bird and 19-21:dog. The range 16-17 is invalid. Here's how you can map this:

    var ranges = []int{-1, 4, 8, 15, 18, 21, 22}
    var names = []string{"", "dog", "cat", "bird", "", "dog", "bird", ""}
    

    There is an empty "" name for the range between 15 and 18. Testing it:

    nums := []int{15, 16, 19}
    for _, n := range nums {
        if name := getName(n); name == "" {
            fmt.Printf("Invalid number: %4d
    ", n)
        } else {
            fmt.Printf("Number        : %4d, Name: %s
    ", n, name)
        }
    }
    

    Output (try this variant on the Go Playground):

    Number        :   15, Name: bird
    Invalid number:   16
    Number        :   19, Name: dog
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 抖音咸鱼付款链接转码支付宝
  • ¥15 ubuntu22.04上安装ursim-3.15.8.106339遇到的问题
  • ¥15 求螺旋焊缝的图像处理
  • ¥15 blast算法(相关搜索:数据库)
  • ¥15 请问有人会紧聚焦相关的matlab知识嘛?
  • ¥15 网络通信安全解决方案
  • ¥50 yalmip+Gurobi
  • ¥20 win10修改放大文本以及缩放与布局后蓝屏无法正常进入桌面
  • ¥15 itunes恢复数据最后一步发生错误
  • ¥15 关于#windows#的问题:2024年5月15日的win11更新后资源管理器没有地址栏了顶部的地址栏和文件搜索都消失了