Одно из возможных решений
Вы можете сохранить положение строки в дескрипторе входного файла, а также 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
введите, если вы положили \n
обратно, когда вы print
.В любом случае, она всегда одинаковой длины.Если вы это сделаете, вам следует print
a $/
, который является разделителем входных записей , который chomp
удален, или вы фальсифицируете свои данные.