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;
    }
}