如何解决如何从Perl中的哈希获取小于阈值的第一个值
我有一个哈希,其中包含unixtime作为键,而volume作为值。
我需要从其中小于卷threshold
值(我在开始时定义的阈值)的哈希中获取unixtime和卷对,并且该对发生在哈希的第一位。
下面是我的脚本:
use strict;
use warnings;
use Data::Dumper;
use List::Util qw(reduce);
use POSIX qw( strftime );
my $threshold = 20;
my %hash = (
'1596561300' => '19','1596561306' => '12','1596561312' => '17','1596561318' => '20','1596561324' => '23','1596561330' => '11','1596561336' => '16','1596561342' => '15','1596561348' => '13','1596561354' => '17'
);
my $key = reduce { $hash{$a} <= $hash{$b} ? $a : $b } keys %hash;
my $val = $hash{$key};
$key = strftime("%Y-%m-%d %H:%M:%S",localtime($key));
print "Key=>$key :: Value=>$val\n";
在上面的脚本中,我能够从哈希的所有值(卷)中获取unixtime,最小哈希值的卷。即
Key=>2020-08-04 18:15:30 :: Value=>11
但是我需要获取小于第一个/最小哈希键中出现的阈值的值。
对于上面的示例,它应获取('1596561300'=>'19'),即:
Key=>2020-08-04 18:15:00 :: Value=>19
我该如何获取? TIA。
解决方法
基本上,您要做的就是遍历哈希,检查值是否在阈值以下,并记住符合该条件的最早时间戳:
#!/usr/bin/env perl
use strict;
use warnings;
use POSIX qw( strftime );
my $threshold = 20;
my %hash = (
'1596561300' => '19','1596561306' => '12','1596561312' => '17','1596561318' => '20','1596561324' => '23','1596561330' => '11','1596561336' => '16','1596561342' => '15','1596561348' => '13','1596561354' => '17'
);
my $earliest;
for (keys %hash) {
# Ignore any entries with a volume above the threshold
next if $hash{$_} >= $threshold;
$earliest //= $_; # Initialize it if it doesn't have a value yet
$earliest = $_ if $_ < $earliest;
}
die "No volumes under threshold" unless defined $earliest;
my $formatted = strftime("%Y-%m-%d %H:%M:%S",localtime($earliest));
print "Key=>$formatted :: Value=>$hash{$earliest}\n";
,
您可以通过检查值是否小于阈值以及密钥是否小于上次捕获的密钥来遍历哈希(不进行排序)。
我只是在没有语法检查或编译器的情况下将其丢弃:
my $threshold = 20;
my $last;
for my $key (keys %hash) {
if ($hash{$key} <= $threshold && $key < ($last //= $key)) {
$last = $key;
}
}
if ($last) {
printf "Key=>%s :: Value=>%s\n",strftime("%Y-%m-%d %H:%M:%S",localtime($last)),$hash{$last};
}
,
您可以使用https://metacpan.org/pod/List::Util#pairmap
提供的pairmap和unpairs方法pairmap:类似于perl的map关键字,但是将给定列表解释为偶数大小的对列表。它会在列表上下文中多次调用BLOCK,将$ a和$ b设置为@kvlist中的连续值对。返回列表上下文中BLOCK返回的所有值的串联或标量上下文中返回的项目。
unpairs:成对的逆函数;此函数获取一个包含两个元素的ARRAY引用列表,并返回每个对中两个值的扁平列表,
use strict;
use warnings;
use List::Util qw(pairmap unpairs min);
use POSIX qw( strftime );
use Data::Dumper qw(Dumper);
my $threshold = 20;
my %hash = (
'1596561300' => '19','1596561200' => '12','1596561354' => '17'
);
# my @list = pairmap { BLOCK } @kvlist;
# parimap invokes the BLOCK multiple times => checking value equal to threshold-1
# and retrun list
# my @kvlist = unpairs @pairs
# unpair method takes a list of ARRAY references containing two elements each,# and returns a flattened list of the two values from each of the pairs,my %h = unpairs (pairmap { ($b == ($threshold-1)) ? [$a,$b] : () } %hash);
# if hash is having mutiple same values then get min key from hash
if (%h) {
my $min_key = min(keys(%h));
print "\n Key : ",localtime($min_key))," and Value :",$h{$min_key},"\n";
} else {
print "\n Not found data \n";
}
输出
Key : 2020-08-04 22:45:00 and Value :19
,
我认为您无法避免按键对哈希进行排序:
foreach my $k (sort keys %hash) {
if( $hash{$k} <= $threshold ) {
print "Key=>",localtime($k)),":: Value=>",$hash{$k},"\n";
last;
}
}
,
您可以反转哈希值以翻转键和值,然后从阈值开始倒数,直到找到存在的那个。
9
我认为我以前从未使用过until
,但这似乎比my %reversed = reverse %hash;
my $needle = $threshold - 1;
$needle-- until exists $reversed{$needle};
my $key = strftime("%Y-%m-%d %H:%M:%S",localtime($reversed{$needle}));
my $val = $needle;
print "Key=>$key :: Value=>$val\n";
读起来更好。
阈值为while not exists
的输出为
20