我有一堆数字时间戳,我想检查一个范围,看看它们是否匹配特定的日期范围。基本上就像在BET中使用BETWEEN .. AND ..匹配。明显的数据结构将是B树,但虽然CPAN上有许多B树实现,但它们似乎只实现精确匹配。 Berkeley DB有同样的问题;有B树索引,但没有范围匹配。
最简单的方法是什么?除非必须,否则我不想使用SQL数据库。
澄清:我有很多这些,所以我正在寻找一个高效的方法,而不仅仅是grep over a array。
答案 0 :(得分:3)
grep
会很快,即使是数百万也是如此。
# Get everything between 500 and 10,000:
my @items = 1..1_000_000;
my $min = 500;
my $max = 10_000;
my @matches = grep {
$_ <= $max && $_ >= $min
} @items;
在time
下运行我明白了:
time perl million.pl
real 0m0.316s
user 0m0.210s
sys 0m0.070s
答案 1 :(得分:2)
时间戳是数字。为什么不是常见的数值比较运算符,如&gt;和&lt; ?
如果你有很多时间戳,如果你只想过滤一次,那么问题就没那么了。它是O(n),其他所有方法都会更长。
另一方面,对于要从中提取多个不同范围的大集合,首先对项目进行排序可能更有效。调用搜索m的数量,直接过滤的复杂度将为O(m.n)。使用sort然后搜索它可能是O(n.log(n)+ m.log(n)),这通常要好得多。
任何O(n.log(n))排序方法都可以,包括使用内置的排序运算符(或者你建议的b-tree)。有效排序方法之间的主要区别在于你的记忆是否可以保持你的全套。我有一个内存bootleneck来保存内存中的数据和密钥(时间戳),你只能保留内存中的数据的时间戳和一些索引以及其他地方的真实数据(磁盘文件,数据库)。但是如果你的数据集确实如此之大,那么最有效的解决方案可能是将整个数据集放在数据库中并使用时间戳索引(使用perl可以很容易地与数据库绑定)。
然后你将拥有你的范围。您只需使用双向搜索来查找范围和最后一个元素中包含的第一个元素的索引,复杂度将为O(log(n))(如果进行线性搜索,则排序的整个目的将被取消)。 / p>
下面在时间戳数组上使用sort和binary_search的示例,将使用扩展到具有时间戳和内容的某些数据结构仍然是一个练习。
use Search::Binary;
my @array = sort ((1, 2, 1, 1, 2, 3, 2, 2, 8, 3, 8, 3) x 100000);
my $nbelt = @array;
sub cmpfn
{
my ($h, $v, $i) = @_;
$i = $lasti + 1 unless $i;
$record = @array[$i||$lasti + 1];
$lasti = $i;
return ($v<=>$record, $i);
}
for (1..1){
$pos = binary_search(1, $nbelt, 2, \&cmpfn);
}
print "found at $pos\n";
答案 2 :(得分:1)
我没用过它。但是在搜索CPAN时发现了这一点。这可能会提供您想要的。您可以使用Tree :: Binary构建数据,并使用Tree :: Binary :: Visitor :: Base子类来进行范围查询。
其他简单方法是使用SQLite。