【问题标题】:How to search within list of integer ranges efficiently - java如何有效地在整数范围列表中搜索 - java
【发布时间】:2021-05-22 09:34:42
【问题描述】:

如何在整数范围列表中高效搜索?

我有一些重复值的范围列表。如果输入数字在范围内,我想获取 值。

例如

Range Start Range End Value
10 75 A
95 200 A
300 455 B
570 650 C
201 250 A
255 275 B

注意:开始和结束范围不重叠。

  • 输入 260 预期输出 B
  • 输入 195 预期输出 A

目前,我正在 HashMap 中保存并存储 {“10-75” , A} {'95-200”, B}... 我是

  • 循环遍历 Map 的所有键,
  • 拆分每个键,
  • 转换为 int 和
  • 检查给定的数字是否在范围内。
  • 如果是,则获取该键的值

我认为在 Java 中可能有一些更有效的方法来处理这个问题。

任何帮助将不胜感激。

【问题讨论】:

  • 看看这里使用树形结构。
  • 如果我没看错的话,即使只有六个ifs 检查一个数字是否在某个范围内,也比使用地图更有效。也许不优雅,但肯定是高效的。
  • 如果范围列表很小,我会使用if。我的清单有数百个。:(

标签: java list hashmap range


【解决方案1】:

你可以使用Guava的RangeMap:

RangeMap<Integer, Character> rangeMap = TreeRangeMap.create();
rangeMap.put(Range.closed(10, 75), 'A');
rangeMap.put(Range.closed(95, 200), 'A');
rangeMap.put(Range.closed(300, 455), 'B');
rangeMap.put(Range.closed(570, 650), 'C');
rangeMap.put(Range.closed(201, 250), 'A');
rangeMap.put(Range.closed(255, 275), 'B');

Character character = rangeMap.get(61);
Character character2 = rangeMap.get(244);
Character character3 = rangeMap.get(270);

System.out.println(character);
System.out.println(character2);
System.out.println(character3);

输出:

A
A
B

注意:由于某种原因,它被标记为@Beta https://github.com/google/guava/issues/3376,所以我想确保它可以用于生产用途。

【讨论】:

  • 谢谢。感谢您的帮助。
  • 对于在 Java 中相对简单的事情,我质疑使用 3rd 方库只是为了获得此功能(当然,除非 OP 已经在使用 Guava)。
【解决方案2】:

为什么不尝试三个 if-else 语句?

假设:范围的开始值和结束值被视为给定范围内的值。

'D'表示给定值不属于定义的范围值。

示例代码:

 public static char findRangeValue(int number){

        if((number >= 10 && number <=75) ||(number >= 95 && number <=250) ){
            return 'A';
        }else if((number >= 255 && number <=275) ||(number >= 300 && number <=455)  ){
            return 'B';
        }else if(number >= 570 && number <=650 ){
            return 'C';
        }
           return 'D';
    }

示例方法调用和输出:

  public static void main(String[] args) {

        System.out.println(findRangeValue(265));
        System.out.println(findRangeValue(11));
        System.out.println(findRangeValue(575));
    }

输出:

B
A
C

【讨论】:

  • 谢谢。我的实际范围列表是数百个。对于我的情况,这可能不是优雅的解决方案/
【解决方案3】:

您可以使用 TreeMap 和 Entry 像这样使用常规 Java 来做到这一点。 如果提供的参数不存在范围,则返回 Not Found

这是包含范围的地图。

  • 这是一个树形图
  • 键是范围的下半部分。
  • 值为AbstractMap.SimpleEntry,包含范围的上半部分和字符串。
NavigableMap<Integer, AbstractMap.SimpleEntry<Integer,String>> nmap =
        new TreeMap<>();

构建地图的方法。

public static void build(
        NavigableMap<Integer, AbstractMap.SimpleEntry<Integer, String>> map,
                                         int start, int end, String v) {
        AbstractMap.SimpleEntry<Integer, String> e = new 
                    AbstractMap.SimpleEntry<Integer,String>(end,v);
        map.put(start, e);
}

用于检索字符串的 lambda。

Function<Integer,String> get = k->{
        Entry<Integer, AbstractMap.SimpleEntry<Integer,String>> entry = 
                             nmap.floorEntry(k);
        if (entry == null) {
                  return "Not Found";
        }
        if (k > entry.getValue().getKey()) {
                  return "Not Found";
        }
        return entry.getValue().getValue();        
};

为每个范围构建地图

build(nmap, 10, 75, "A");
build(nmap, 95, 200, "A");
build(nmap, 300, 455, "B");
build(nmap, 570, 650, "C");
build(nmap, 201, 250, "A");
build(nmap, 255, 275, "B");

测试

int[] testData = { 9, 23, 255, 99, 94, 201 };
for (int i : testData) {
    System.out.printf("%4d -> %s%n",i, get.apply(i));
}
    

打印

   9 -> Not Found
  23 -> A
 255 -> B
  99 -> A
  94 -> Not Found
 201 -> A

【讨论】:

    猜你喜欢
    • 2016-02-04
    • 2012-05-26
    • 1970-01-01
    • 2017-01-24
    • 2019-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多