【问题标题】:How to get the top keys from a hash by value如何按值从哈希中获取顶部键
【发布时间】:2012-11-21 16:05:26
【问题描述】:

我有一个按从大到小排序的哈希值。我将如何获得前 5 名?这里有一篇文章谈到只获得一个值。

What is the easiest way to get a key with the highest value from a hash in Perl?

我明白,所以可以说让这些值将它们添加到数组中并删除散列中的元素,然后再次执行该过程?

似乎应该有一种更简单的方法来做到这一点。

我的哈希称为 %words。

已编辑在实际上不需要它的情况下取出代码作为问题的答案。

【问题讨论】:

  • `"我有一个已排序的哈希值.." 不,您不能对哈希值进行排序。
  • 不,你不能,我的意思是我按顺序打印它们,但我想获得价值最高的前 5 个。
  • s/[\,|\.|\!|\?|\:|\;|\"]//g 不应在字符类括号内使用交替,也不需要转义字符(-] 除外):s/[,.!?:;"]//g for @words。或使用tr/,.!?:;"//d
  • 嗯...您已经将键排序到数组 @keys 中。您只需要从该数组中获取前五个元素。

标签: perl hash key-value


【解决方案1】:

如果性能不是什么大问题

(sort {$words{$a} <=> $words{$b}} keys %words)[0..4])

如果您绝对需要杀手级的速度,那么在 5 次迭代后终止的选择排序可能是您的最佳选择。

my @results;
for (0..4) {
  my $maxkey;
  my $max = 0;

  for my $key (keys %words){
    if ($max < $words{$key}){
      $maxkey = $key;
      $max = $words{$key};
     }
  }
  push @results, $maxkey;
  delete $words{$maxkey};
}

say join(","=>@results);

【讨论】:

  • 速度现在不是一个真正的问题,但我会研究速度的方式,因为我正在大规模做的事情需要速度。感谢您的帮助。
【解决方案2】:

您的问题是如何从哈希中获取五个最高值。你有这个代码:

my @keys = sort {
    $words{$b} <=> $words{$a}
    or
    "\L$a" cmp "\L$b"
} keys %words;

您的排序哈希键在哪里。从那里拿五个最上面的钥匙?

my @highest = splice @keys, 0, 5;  # also deletes the keys from the array
my @highest = @keys[0..4];         # non-destructive solution

您的代码中还有一些 cmets:

open( my $filehandle0, '<', $file0 ) || die "Could not open $file0\n";

最好在您的 die 语句中包含错误消息 $! 以获取有关打开失败原因的有价值信息。

for (@words) {
    s/[\,|\.|\!|\?|\:|\;|\"]//g;
}

就像我在评论中所说,您不需要转义字符或在字符类括号中使用交替。使用任一:

s/[,.!?:;"]//g for @words;   #or
tr/,.!?:;"//d  for @words;

下一部分有点奇怪。

my @stopwords;
while ( my $line = <$filehandle1> ) {
    chomp $line;
    my @linearray = split( " ", $line );
    push( @stopwords, @linearray );
}
for my $w ( my @stopwords ) {
    s/\b\Q$w\E\B//ig;
}

您从文件中读取停用词...然后从$_ 中删除停用词?你现在还在使用$_ 吗?此外,您正在循环头中重新声明 @stopwords 数组,这实际上意味着您的新数组将为空,并且您的循环将永远不会运行。这个错误似乎是无声的,所以你可能永远不会注意到。

my %words = %words_count;

在这里复制%words_count,这似乎是多余的,因为你再也不会使用它了。如果散列很大,这会降低性能。

my $key_count = 0;
$key_count = keys %words;

这可以在一行中完成:my $key_count = keys %words。在我看来,更具可读性。

$value_count = $words{$key} + $value_count;

也可以缩写为+= 运算符:$value_cont += $words{$key}

使用严格和警告非常好。

【讨论】:

  • 您非常有帮助。你回答的比我问的多。谢谢你指出我的缺点。我使用了很多我在网上阅读或看到的东西。然后我将其调整为我的代码。在做这个项目的过程中,我真的学到了很多东西。感谢您的帮助。干杯。
  • 虽然我不确定我的停用词有什么不好。
  • 默认情况下将替换应用于$_,因此s/foo// 表示$_ =~ s/foo//。在您的循环中,我不知道您指的是哪个$_。如果打算将其应用于$w,那么您只是从@stopwords 数组中删除所有内容。
  • 我这样做的目的是确保没有一个停用词已经在 perl 中声明为运算符。我在某处读到,这是一个很好的实践。但是,也许我以错误的方式应用它。
  • 我假设您的意思是元字符。但这并不重要,除非您在正则表达式中使用它们。哈希键中使用的任何字符都是文字,所以不用担心。
【解决方案3】:

有一个 CPAN 模块,Sort::Key::Top。 它具有直接的界面和高效的 XS 实现:

use Sort::Key::Top qw(rnkeytop);

my @results = rnkeytop { $words{$_} } 5 => keys %words;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-23
    • 2012-08-17
    • 2021-12-30
    • 2011-05-21
    • 2010-12-19
    • 2020-11-24
    • 1970-01-01
    • 2015-10-17
    相关资源
    最近更新 更多