首页 > 解决方案 > 在保持顺序的同时按值长度对哈希进行排序

问题描述

我目前正在编写一个 Perl 脚本来对标准输入中的行进行排序并按行长的顺序打印这些行,同时保留相等的行的顺序。我的排序代码包括以下内容:

while (my $curr_line = <STDIN>) {
    chomp($curr_line);
    $lines{$curr_line} = length $curr_line;
}

for my $line (sort{ $lines{$a} <=> $lines{$b} } keys %lines){
    print $line, "\n";
}

例如,我的标准输入由以下内容组成:

tiny line
medium line
big line
huge line
rand line
megahugegigantic line

我会得到以下输出:

big line
rand line
tiny line
huge line
medium line
megahugegigantic line

有什么办法可以保留等长线的顺序,以便小号出现在大号之前,然后大号出现在兰特之前?此外,每次我运行脚本时,顺序似乎都会发生变化。

提前致谢

标签: perlsortinghashkey

解决方案


一种可能的解决方案

您可以将行的位置保存在输入文件句柄以及length. 魔术$.变量(输入行号提供了这一点。然后,您可以对这两个值进行排序。

use strict;
use warnings;

my %lines;
while ( my $curr_line = <DATA> ) {
  chomp($curr_line);
  $lines{$curr_line} = [ length $curr_line, $. ];
}

for my $line (
  sort {
       $lines{$a}->[0] <=> $lines{$b}->[0]
    || $lines{$a}->[1] <=> $lines{$b}->[1]
  } keys %lines
) {
  print $line, "\n";
}

__DATA__
tiny lin1
medium line
big line
huge lin2
rand lin3
megahugegigantic line

这将始终输出

big line
tiny lin1
huge lin2
rand lin3
medium line
megahugegigantic line

当然,您也可以使用散列来使代码更具可读性。

$lines{$curr_line} = { 
  length   => length $curr_line, 
  position => $., 
};

您的实施说明

由于随机哈希排序,您的结果每次都会更改顺序。keys由于 Perl 实现散列的方式,返回键列表的方式是随机的。这是设计使然,并且是一项安全功能。由于存在多个具有相同值的键,因此排序有时会返回不同的结果,具体取决于哪个相等值的键首先出现。

你可以通过在你的电话sort前面加上另一个来缓解这种情况。keys这将按名称对键进行排序,至少使不需要的结果的顺序保持一致。

#                                               vvvv
for my $line (sort{ $lines{$a} <=> $lines{$b} } sort keys %lines) { ... }

请注意,chomp如果您\nprint. 无论如何,它总是相同的长度。如果这样做,您应该print使用$/,这是删除的输入记录分隔符chomp否则您会伪造数据。


推荐阅读