我当前正在编写一个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
我有什么办法可以保留等长线的顺序,以使细线先于大字而先于兰特?另外,每次我运行脚本时,顺序似乎都会改变。
预先感谢
答案 0 :(得分:3)
您可以将行的位置以及length
保存在输入文件句柄中。 $.
magic variable (input line number)提供了这一点。然后,您可以对两个值进行排序。
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 => $.,
};
由于随机哈希排序,您的结果每次都会更改其顺序。由于Perl实现散列的方式,keys
返回键列表的方式是随机的。这是设计使然,并且具有安全性功能。由于存在多个具有相同值的键,因此排序有时会返回不同的结果,具体取决于哪个等值键首先出现。
您可以通过在通话sort
之前附加另一个keys
来减轻这种情况。这样就可以按名称对键进行排序,至少可以使不需要的结果的顺序保持一致。
# vvvv
for my $line (sort{ $lines{$a} <=> $lines{$b} } sort keys %lines) { ... }
请注意,如果在\n
时放回print
,则不必chomp
输入。无论如何,它总是一样长。如果这样做,您应该print
$/
(chomp
被删除的input record separator)中伪造数据,或者您伪造数据。
答案 1 :(得分:2)
排序不是问题,Perl使用了稳定排序的快速排序算法,匹配相同排序键的输入在排序输出上的顺序与输入的顺序相同。
您的问题是您将这些行存储在哈希中。哈希是键值对的无序集合,因此将行添加到哈希中,然后再次将它们打印出来而不进行排序将使您以随机顺序获得行。
您需要将所有行读入数组,然后按长度排序,最快的方法是使用Schwartzian Transformation,请参见下文。
my @lines = <STDIN>;
chomp(@lines);
my @sorted = # This is the clever bit and needs to be red from the last map up
map { $_->[0] } # Get the lines
sort { $a->[1] <=> $b->[1] } # Sort on length
map { [$_, length $_] } # Create a list of array refs containing
# the line and the length of the line
@lines;
print join "\n", @sorted; # print out the sorted lines
答案 2 :(得分:2)
您无法在任何地方存储原始订单,因此无法对其进行排序。最简单的解决方法是将行存储在数组中,并确保Perl使用稳定的排序。
use sort 'stable';
my @lines = <>;
chomp(@lines);
for my $line ( sort { length($a) <=> length($b) } @lines) {
say $line;
}
[ ST在这方面过大了。太夸张了,它甚至可能使速度变慢!]
答案 3 :(得分:1)
正如已经解释的那样,随机性来自于您使用哈希键存储字符串。不需要这个,或者像 Schwartzian变换这样更复杂的东西来完成这项工作
v5.8以后的所有Perl版本都使用了 stable 排序,它将保留按相同顺序均等排序的值。但是您可以坚持使用sort
杂用语和{p>
sort
这是我编写程序的方式。它会在文件末尾停止读取输入,或者在您希望从键盘输入数据的情况下看到空白行时停止读取
use sort 'stable'
使用与您在问题中使用的输入相同的输入,会产生
use strict;
use warnings 'all';
use feature 'say';
use sort 'stable';
my @list;
while ( <> ) {
last unless /\S/;
chomp;
push @list, $_;
}
say for sort { length $a <=> length $b } @list;