Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用java映射进行范围搜索_Java_Maps - Fatal编程技术网

使用java映射进行范围搜索

使用java映射进行范围搜索,java,maps,Java,Maps,我有一个用例,如果一个数字在0-10之间,它应该返回0,如果它在11-20之间,它应该返回1,以此类推 0 => 0-3, (0 and 3 are inclusive) 1 => 4-15, (4 and 15 are inclusive) 2 => 16-40, (16 and 40 are inclusive) 3 => 41-88, (41 and 88 are inclusive) 5 => 89-300 (89 and 300 are inclusive

我有一个用例,如果一个数字在0-10之间,它应该返回0,如果它在11-20之间,它应该返回1,以此类推

0 => 0-3, (0 and 3 are inclusive)
1 => 4-15, (4 and 15 are inclusive)
2 => 16-40, (16 and 40 are inclusive)
3 => 41-88, (41 and 88 are inclusive)
5 => 89-300 (89 and 300 are inclusive)
我在考虑如何实现java映射,但它不允许范围搜索

我对这样的东西感兴趣,我有一个函数

int foo() {

}
如果foo返回5,因为它位于0到10之间,所以我将使用0,如果foo返回25,则使用2

有什么想法吗


编辑:实际上,范围没有0-10、11-20那么简单。我希望能够进行范围搜索。很抱歉搞混了。根据我添加的正确示例的查询,数字是连续的

我认为您想要的是类似于
foo()/10
的内容,但这将使您的范围与您要求的范围略有偏差。如果“地图”中的每个项目不遵循简单的模式,则始终可以对它们的两个端点进行比较。

在无法用算术解决的更一般情况下,可以使用适当的比较器创建树形图。为边界值添加映射,然后使用ceilingEntry或floorEntry找到合适的匹配项。

对于范围不一致且存在“漏洞”的更一般问题,我可以想出一些可能的解决方案。最简单的是:

  • 只需为所有有效键值填充一个映射,多个键映射到同一个值。假设您使用HashMaps,这应该是时间效率最高的(O(1)查找),尽管您在设置时有更多的工作,并且使用了更多的空间
  • 使用导航地图并使用
    floorEntry(键)
    进行查找。这应该是更少的时间效率(O(log(N)查找),但更节省空间
  • 这里有一个使用NavigableMap的解决方案,允许在映射中出现“洞”

    private static class Range {
       public int upper, value;
       ...
    }
    
    NavigableMap<Integer, Range> map = new TreeMap<Integer, Range>();
    map.put(0, new Range(3, 0));       // 0..3     => 0
    map.put(5, new Range(10, 1));      // 5..10    => 1
    map.put(100, new Range(200, 2));   // 100..200 => 2
    
    // To do a lookup for some value in 'key'
    Map.Entry<Integer,Range> entry = map.floorEntry(key);
    if (entry == null) {
        // too small
    } else if (key <= entry.getValue().upper) {
        return entry.getValue().value;
    } else {
        // too large or in a hole
    }
    
    私有静态类范围{
    公共价值;
    ...
    }
    NavigableMap=newtreemap();
    put(0,新范围(3,0));//0..3=>0
    put(5,新范围(10,1));//5..10=>1
    put(100,新范围(200,2));//100..200=>2
    //在“键”中查找某个值的步骤
    Map.Entry=Map.floorEntry(键);
    if(条目==null){
    //太小
    }否则,如果(键0
    map.put(5,1);/5..10=>1
    map.put(11,2);/11..200=>2
    //在“键”中查找某个值的步骤
    如果(键<0 | |键>200){
    //超出范围
    }否则{
    返回map.floorEntry(key.getValue();
    }
    
    伪代码:

  • 将范围边界存储在平面数组中:
    newint[]{0,3,5,15,100,300}
  • 在数组中进行二进制搜索,就像在数组中插入数字一样。请参阅
  • 如果插入点为偶数,则该数字不适合任何范围
  • 如果插入点是奇数,则它适合相应的范围。例如,上面数组中
    10
    的插入点将是
    3
    ,将其置于
    5
    15
    之间,因此它属于第二个范围

  • 我认为最简单的解决方案是将范围上限的映射添加到范围映射到的值,然后继续增加数字(映射中的键),直到达到映射(即数字所在范围的上限)

    另一种方法是使用范围内的所有条目填充映射,并为每个条目添加映射

    哪一个更有效取决于您可能需要重复请求某个范围内的所有数字(使用后一种解决方案),还是只请求其中一些数字几次(使用第一种)

    基于此,我需要类似的东西来进行日期范围搜索,该搜索包含与日期范围相关联的数据……以下是我如何应用它的示例。“日期”将是您的键,“范围数据”将是相关联的数据

      long[] dates = new long[] {
        Instant.parse("1900-01-01T00:00:00Z").toEpochMilli(),
        Instant.parse("1950-01-01T00:00:00Z").toEpochMilli(),
        Instant.parse("1960-01-01T00:00:00Z").toEpochMilli(),
        Instant.parse("1970-01-01T00:00:00Z").toEpochMilli(),
        Instant.parse("1980-01-01T00:00:00Z").toEpochMilli(),
        Instant.parse("1990-01-01T00:00:00Z").toEpochMilli(),
        Instant.parse("2000-01-01T00:00:00Z").toEpochMilli(),
        Instant.parse("2010-01-01T00:00:00Z").toEpochMilli()
      };
      String[] rangeData = new String[] {
        "Before 1900 data", "Before 1950 data", "Before 1960 data", 
        "Before 1970 data", "Before 1980 data", "Before 1990 data", 
        "Before 2000 data", "Before 2010 data"
      };
      
      long searchDate = Instant.parse("1949-02-15T00:00:00Z").toEpochMilli();
      int result = Arrays.binarySearch(dates, searchDate);
      
      System.out.println("Result: " + result); 
      if (result == dates.length) {
          System.out.println("Date is after all ranges");
          System.out.println("Data: none");
      }
      else if (result >= 0) {
          System.out.println("Date is an exact match of " + Instant.ofEpochMilli(dates[result]));
          System.out.println("Data: " + rangeData[result]);
      }
      else {
          int resultIndex = Math.abs(result) - 1;
          System.out.println("Date is before idx: "+ resultIndex + " date " + Instant.ofEpochMilli(dates[resultIndex]));
          System.out.println("Data: " + rangeData[resultIndex]);
      }
    
    结果

    Result: -2
    Date is before idx: 1 date 1950-01-01T00:00:00Z
    Data: Before 1950 data
    

    请提供一个你想要做什么的真实示例。示例中给出的范围不是连续的。如果搜索4或50,你想要一个
    null
    结果,上面、下面或最近的范围,还是什么?@mkal:你不断更改要求的方式,你可能是地狱里的经理:-)如果这增加了太多的混乱,我深表歉意:)注意:这只在我们映射到整数
    {0,1,2,…}
    时有效。对于更一般的情况,应该使用某种类型的映射。这非常好地利用了现有的树映射来进行简单的范围搜索。请注意,如果存在重叠的间隔,则该方法将返回该间隔,并使用最接近查找键的下键。类似地,此方法不支持搜索包含给定搜索键的所有重叠间隔,如中所述。如果存在重叠范围,则(很可能)错误指定了这些范围。至少,这是我对这个问题的理解。
    Result: -2
    Date is before idx: 1 date 1950-01-01T00:00:00Z
    Data: Before 1950 data