Вставка и перебор хеша массивов
У меня есть следующие входные данные
Country1:operator1
Country1:operator2
Country1:operator3
Country2:operator1
Country2:operator2
Country2:operator3
Я хотел бы вставить эти данные в хэш %INFO
так что каждый ключ соответствует массиву "операторов", поэтому я мог бы выполнить итерацию следующим образом
foreach $i ( keys %INFO ) {
foreach $operator ( $INFO{$i} ) {
print " $i ---> $operator \n";
}
}
Вот мое собственное решение, которое не работает должным образом
open($fh, "$info_file");
while (my $row = <$fh>) {
chomp $row;
@tokens = split(":",$row);
$name = $tokens[0];
$operator = $tokens[2];
if ($name =~ /^[A-Z]/) {
if ( exists $INFO{$name} ) {
$ptr = \$INFO{$name};
push(@ptr, $operator);
}
else {
@array = ( "$operator" );
$INFO{$name} = [ @array ];
}
}
}
close($f);
3 ответа
Боюсь, ты слишком усложняешь.
open my $fh, '<', $info_file or die "Can't open '$info_file': $!";
my %info;
while (<$fh>) {
next unless /^[A-Z]/;
chomp;
my ($name, $operator) = split /:/;
push @{ $info{$name} }, $operator;
}
И чтобы получить к нему доступ:
foreach my $i (keys %info) {
foreach my $op (@{ $info{$i} }) {
say "$i ----> $op";
}
}
Если вы обрабатываете значение хеш-функции так, как будто это ссылка на массив, то Perl сделает его ссылкой на массив.
См. Поваренную книгу Perl Data Structures для более подробной информации.
Хорошо, во-первых, в этом коде много ошибок, используйте три входных формы open и не заключайте в кавычки переменные по умолчанию, Perl знает, когда все должно быть строками. Так open($fh,"$info_file");
должно быть open($fh, '<', $info_file);
Второй разделитель не возвращает символ разделителя по умолчанию, поэтому $operator = $tokens[2];
должно быть $operator = $tokens[1];
В-третьих, почему вы игнорируете страны, которые не начинаются с А до Я в вашем файле?
Четвертое использование авто вивификации, так что весь if else
блок можно заменить на push @{$INFO{$name}}, $operator
пятый $ptr
а также @ptr
являются отдельными переменными, присваивающими ссылку на массив $ptr
не делает его доступным в @ptr
также \$INFO{$name}
принимает ссылку на то, что когда-либо $INFO{$name}
есть, который в вашем случае уже является ссылкой на массив, так что вы получаете ссылку на ссылку на массив в $ptr
это должно было быть написано $ptr = $INFO{$name};
если вы сохраняете этот код.
Шестое присваивание @array является избыточным, две строки в предложении else должны были быть написаны $INFO{$name} = [ $operator ];
Со всеми этими изменениями вы получаете
open($fh, '<', "$info_file");
while (my $row = <$fh>) {
chomp $row;
my @tokens = split(":",$row);
$name = $tokens[0];
$operator = $tokens[1];
if ($name =~ /^[A-Z]/) {
push @{$INFO{$name}}, $operator;
}
}
close($f);
Вы очень близки, но нет необходимости явно использовать ссылки или инициализировать значение хеш-функции в пустой массив
Это все что тебе нужно
use strict;
use warnings 'all';
open my $fh, '<', $info_file or die $!;
my %info;
while ( <$fh> ) {
chomp;
my ($name, $operator) = split /:/;
push @{ $info{$name} }, $operator if $name =~ /^[A-Z]/;
}