Java 使用Collections.binarySearch()进行谓词搜索(即,不完全匹配)
我有一个按升序排序的时间戳列表:Java 使用Collections.binarySearch()进行谓词搜索(即,不完全匹配),java,collections,binary-search,java-time,Java,Collections,Binary Search,Java Time,我有一个按升序排序的时间戳列表: List<Instant> timestamps = ...; // note: sorted in ascending order 这是解决这个问题的正确(有效)方法,还是我忽略了一个更好的选择?注意,调用查找(即时) >将大大超过时间戳中元素的数量,这就是为什么我认为排序时间戳所引起的开销是必要的。 集合。如文档中所述,如果没有找到精确匹配,它将返回-1-i,其中i是列表中下一个更高元素的索引 只需按自然顺序搜索输入。如果找不到它,那么您可以
List<Instant> timestamps = ...; // note: sorted in ascending order
这是解决这个问题的正确(有效)方法,还是我忽略了一个更好的选择?注意,调用<代码>查找(即时)> >将大大超过<代码>时间戳中元素的数量,这就是为什么我认为排序<代码>时间戳所引起的开销是必要的。
<代码>集合。如文档中所述,如果没有找到精确匹配,它将返回
-1-i
,其中i
是列表中下一个更高元素的索引
只需按自然顺序搜索输入
。如果找不到它,那么您可以从输入
(只需执行-1-resultOfBinarySearch
)中导出下一个更高的即时
索引。如果该索引处的即时
是之前(inputs.plusMillis(CONSTANT))
,则完成,否则,不存在此类即时
我确实认为,您现有的解决方案在某些方面滥用了
binarySearch
,这是为了它的价值。集合。binarySearch
不必用于精确匹配。如文档中所述,如果没有找到精确匹配,它将返回-1-i
,其中i
是列表中下一个更高元素的索引
只需按自然顺序搜索输入
。如果找不到它,那么您可以从输入
(只需执行-1-resultOfBinarySearch
)中导出下一个更高的即时
索引。如果该索引处的即时
是之前(inputs.plusMillis(CONSTANT))
,则完成,否则,不存在此类即时
我确实认为您现有的解决方案在某些方面滥用了
binarySearch
,这是值得的。我看不出有什么问题。二进制搜索最坏情况下的性能将是O(logm),而您的比较器将是常数O(1)。@gtgaxiola酷,感谢您的评论!我真的不确定我是否在“滥用”binarySearch(如果有其他更适合此任务的API)。此列表是否有重复项?如果没有,树集将使这更容易。@VGR否,时间戳
将(应该)没有重复项。您可以使用set.floor(inputs)
实现它,然后进行后续检查,查看inputs
在floor
返回元素后的常量是否不超过毫秒?基本上,是的。我看不出有问题。二进制搜索最坏情况下的性能将是O(logm),而您的比较器将是常数O(1)。@gtgaxiola酷,感谢您的评论!我真的不确定我是否在“滥用”binarySearch(如果有其他更适合此任务的API)。此列表是否有重复项?如果没有,树集将使这更容易。@VGR否,时间戳
将(应该)没有重复项。您可以使用set.floor(inputs)
实现它,然后进行后续检查,查看inputs
在floor
返回元素后的常量是否不超过毫秒?非常好,谢谢分享您的想法+1.请允许我再详细说明一下为什么您认为使用binarySearch
会引起关注?我也很好奇。它主要破坏了Comparator
合同。这不是可传递的比较器。特别是因为这可以用一个完全有效的、正常的比较器来解决,这似乎是错误的。嗯,这很尴尬,但我不明白为什么它不是可传递的。。。根据文档,及物性被定义为“((比较(x,y)>0)和&(比较(y,z)>0))
意味着比较(x,z)>0
”。使用上面定义的比较器
,compare(val1,val2)
仅当val1
和val2
位于不同的间隔时才会大于零。因此,要使lhs首先保持不变,x
、y
和z
必须在不同的间隔内,然后compare(x,z)
也将大于0。compare(x,y)
可以0
和compare(y,z)
可以0
但compare(x,z)
可以为非零,例如y=x+SOME_常量-1
和z=y+SOME_常量-1
。感谢分享您的想法+1.请允许我再详细说明一下为什么您认为使用binarySearch
会引起关注?我也很好奇。它主要破坏了Comparator
合同。这不是可传递的比较器。特别是因为这可以用一个完全有效的、正常的比较器来解决,这似乎是错误的。嗯,这很尴尬,但我不明白为什么它不是可传递的。。。根据文档,及物性被定义为“((比较(x,y)>0)和&(比较(y,z)>0))
意味着比较(x,z)>0
”。使用上面定义的比较器
,compare(val1,val2)
仅当val1
和val2
位于不同的间隔时才会大于零。因此,要使lhs首先保持不变,x
、y
和z
必须在不同的间隔内,然后compare(x,z)
也将大于0。compare(x,y)
可以0
和compare(y,z)
可以0
但compare(x,z)
可以为非零,例如y=x+SOME_常量-1
和z=y+SOME_常量-1
。
public class TimestampFinder {
private static final long SOME_CONSTANT = 10_000;
private List<Instant> timestamps = ... ; // initialize and sort
public Instant find(Instant inputTs) {
int index = Collections.binarySearch(timestamps, inputTs, (t, key) -> {
if (t.isBefore(key) && key.isBefore(t.plusMillis(SOME_CONSTANT))) {
// inputTs is part of the duration after t
// return 0 to indicate that we've found a match
return 0;
}
// inputTs not in interval
// use Instant's implementation of Comparator to indicate to binarySearch if it should continue the search in the upper or lower half of the list
return t.compareTo(key);
});
return index >= 0 ? timestamps.get(index) : null;
}
}