如何在Perl中从哈希中获取小于阈值的第一个值

如何在Perl中从哈希中获取小于阈值的第一个值,perl,hash,Perl,Hash,我有一个散列,其中包含unixtime作为键,volume作为值 我需要从散列中获取unixtime和volume对,其中卷小于我在开始时定义的阈值threshold value,并且该对出现在散列的第一位 以下是我的脚本: use strict; use warnings; use Data::Dumper; use List::Util qw(reduce); use POSIX qw( strftime ); my $threshold = 20; my %hash = (

我有一个散列,其中包含unixtime作为键,volume作为值

我需要从散列中获取unixtime和volume对,其中卷小于我在开始时定义的阈值threshold value,并且该对出现在散列的第一位

以下是我的脚本:

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";
但我需要获取小于第一个/最小哈希键中出现的阈值的值

对于上面的示例,它应该获取“1596561300”=>“19”,即:

Key=>2020-08-04 18:15:00 :: Value=>19

我怎么去拿?TIA.

我认为您无法避免按键对哈希进行排序:

foreach my $k (sort keys %hash) {
        if( $hash{$k} <= $threshold ) {
                print "Key=>", strftime("%Y-%m-%d %H:%M:%S", localtime($k)),
                        ":: Value=>", $hash{$k}, "\n";
                last;
        }
}

我认为您无法避免按键对哈希进行排序:

foreach my $k (sort keys %hash) {
        if( $hash{$k} <= $threshold ) {
                print "Key=>", strftime("%Y-%m-%d %H:%M:%S", localtime($k)),
                        ":: Value=>", $hash{$k}, "\n";
                last;
        }
}

您可以反转散列以翻转键和值,然后从阈值向后计数,直到找到一个存在的值

my%reversed=反向%hash; my$Pineder=$threshold-1; $Pionel-直到存在$reversed{$Pionel}; my$key=strftime%Y-%m-%d%H:%m:%S,localtime$reversed{$needle}; 我的$val=$needle; 打印键=>$Key::Value=>$val\n; 我不认为我以前用过,但这似乎比不存在时读得更好

阈值为20的输出为


您可以反转散列以翻转键和值,然后从阈值向后计数,直到找到一个存在的值

my%reversed=反向%hash; my$Pineder=$threshold-1; $Pionel-直到存在$reversed{$Pionel}; my$key=strftime%Y-%m-%d%H:%m:%S,localtime$reversed{$needle}; 我的$val=$needle; 打印键=>$Key::Value=>$val\n; 我不认为我以前用过,但这似乎比不存在时读得更好

阈值为20的输出为


基本上,您需要做的就是通过散列,检查值是否低于阈值,并记住符合该标准的最早时间戳:

#!/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";

基本上,您需要做的就是通过散列,检查值是否低于阈值,并记住符合该标准的最早时间戳:

#!/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};
}

通过检查值是否小于阈值以及密钥是否小于上次捕获的密钥,可以在不进行排序的情况下通过哈希

我只是在没有语法检查或编译器的情况下将其抛出:

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

您可以使用提供的pairmap和unpairs方法

pairmap:类似于perl的map关键字,但将给定的列表解释为大小相等的对列表。它在列表上下文中多次调用块,将$a和$b设置为@kvlist中的连续值对。返回块在列表上下文中返回的所有值的串联,或在标量上下文中返回的项数的计数

unpairs:成对的反函数;此函数获取一个数组引用列表,每个数组引用包含两个元素,并返回每个数组引用对中两个值的展开列表

输出


您可以使用提供的pairmap和unpairs方法

pairmap:类似于perl的map关键字,但将给定的列表解释为大小相等的对列表。它在列表上下文中多次调用块,将$a和$b设置为@kvlist中的连续值对。返回块在列表上下文中返回的所有值的串联,或在标量上下文中返回的项数的计数

unpairs:成对的反函数;此函数获取一个数组引用列表,每个数组引用包含两个元素,并返回每个数组引用对中两个值的展开列表

输出


请注意,只有当所有哈希值都是唯一的时,反转哈希才可靠。如果存在重复项,则使用“反转”将其转换为关键帧会导致关键帧冲突,其中一个将覆盖其他关键帧。在问题的示例数据中,有两个值为17的条目,因此其中一个时间戳丢失。@DaveSherohman true,我没有看到。然而问题是OP想要哪一个。您的解决方案有相同的冲突问题,因为您没有排序。因此,根据Perl版本的密钥顺序,您会得到随机密钥。既然OP没有说他们想要最早的,我想你也在做假设,尽管你的比我的好得多。但我认为问题还不清楚,问题是我需要获取小于第一个/最小散列键中出现的阈值的值,我认为这表明他想要最早的限定时间戳。如果你认为我的答案有问题,请在这里发表评论,因为讨论与你的答案无关。请注意,只有当所有哈希值都为
e独一无二。如果存在重复项,则使用“反转”将其转换为关键帧会导致关键帧冲突,其中一个将覆盖其他关键帧。在问题的示例数据中,有两个值为17的条目,因此其中一个时间戳丢失。@DaveSherohman true,我没有看到。然而问题是OP想要哪一个。您的解决方案有相同的冲突问题,因为您没有排序。因此,根据Perl版本的密钥顺序,您会得到随机密钥。既然OP没有说他们想要最早的,我想你也在做假设,尽管你的比我的好得多。但我认为问题还不清楚,问题是我需要获取小于第一个/最小散列键中出现的阈值的值,我认为这表明他想要最早的限定时间戳。如果你认为我的答案有问题,请在这里发表评论,因为讨论与你的答案无关。你能告诉我你是否有两个条目,如17值“1596561300”=>“19”,这等于2020-0804 22:45 00′=>19,例如‘1596561354’=>19’,相当于“2020-0804 22:45∶54′=>19,在这种情况下,你将考虑哪一个值?”i、 例如,“2020-08-04 22:45:00=>19”。您能告诉我您是否有两个条目,如17值“1596561300”=>19,这等于2020-0804 22:45 00′=>19,例如‘1596561354’=>19’,相当于“2020-0804 22:45∶54′=>19,在这种情况下,你将考虑哪一个值?”i、 e.,'2020-08-04 22:45:00=>19'。
 Key : 2020-08-04 22:45:00 and Value :19