Perl Создание хеш-ссылки и цикл по одному элементу из каждой ветви за раз
Как новичок, я думаю, что это довольно сложная проблема, я надеюсь, что кто-то может помочь.
У меня есть следующий текстовый файл (вкладка разделена)...
fILE1.TXT
Dog Big
Dog Medium
Dog Small
Rabbit Huge
Rabbit Tiny
Rabbit Middle
Donkey Massive
Donkey Little
Donkey Gigantic
Мне нужно прочитать FILE1.txt в ссылку на хэш, чтобы получить что-то вроде следующего... (используя Data::Dumper)
$VAR1 = {
'Dog' => {
'Big',
'Medium',
'Small'
},
'Rabbit => {
'Huge',
'Tiny',
'Middle'
},
'Donkey => {
'Massive',
'Little',
'Gigantic'
},
};
У меня проблема:
Затем мне нужно перебрать каждую ветвь хеш-ссылки по одной, я буду использовать значение из хеш-ссылки, чтобы проверить, соответствует ли это моему ключевому слову, если так, то он вернет соответствующий ключ.... например...
Что мне нужно для этого сделать:
my $keyword == "Little";
Dog->Big
if 'Big' matches my keyword then return $found = Dog
else go to the next branch
Rabbit->Huge
if 'Huge' matches my keyword then return $found = Rabbit
else go to the next branch
Donkey->Massive
if 'Massive' matches my keyword then return $found = Donkey
else go to the next branch (which is Dog again, but the second element this time)
Dog->Medium
if 'Medium' matches my keyword then return $found = Dog
else go to the next branch
Rabbit->Tiny
if 'Tiny' matches my keyword then return $found = Rabbit
else go the the next branch
Donkey->Little
if 'Little' matches my keyword then return $found = Donkey
..... и так далее, пока ключевое слово не будет найдено или мы не достигнем конца ссылки на хеш
Это то, чего я пытаюсь достичь, но я не знаю, как это сделать, или является ли ссылка на хэш лучшим способом сделать это, или если это можно сделать даже с помощью ссылки на хэш / хэш?
Ваша помощь в этом очень ценится, спасибо
2 ответа
Выбор правильной структуры данных часто является ключевым шагом к решению, но прежде всего вы должны определить, чего вы пытаетесь достичь. Какова общая цель? Например, у меня есть этот файл данных, и в моем приложении / программе мне часто приходится запрашивать эту информацию. Очень важно задать правильный вопрос, потому что, например, если вам не нужно часто спрашивать ключевое слово, вообще не имеет смысла создавать хэш.
perl -anE'say $F[0] if $F[1] eq "Little"' FILE1.txt
Да, это так просто. Смотреть в perlrun
man-страница для переключателей и что они означают и как сделать то же самое в большем приложении.
Если вам часто приходится задавать этот вопрос, вы должны расположить свои данные таким образом, чтобы это помогло вам, а не так, как вам придется бороться.
use strict;
use warnings;
use feature qw(say);
use autodie;
open my $f, '<', 'FILE1.txt';
my %h;
while(<$f>) {
chomp;
my ($animal, $keyword) = split' ';
$h{$keyword} = $animal unless exists $h{$keyword};
}
close $f;
for my $keyword (qw(Little Awkward Small Tiny)) {
say $h{$keyword} ? "$keyword $h{$keyword}" : "keyword $keyword not found";
}
Но если вы все еще настаиваете, что хотите пересечь хеш, вы можете сделать это, но вас предупредили.
open my $f, '<', 'FILE1.txt';
my %h;
while (<$f>) {
chomp;
my ( $animal, $keyword ) = split ' ';
push @{ $h{$animal} }, $keyword;
}
close $f;
KEYWORD:
for my $keyword (qw(Little Awkward Small Tiny)) {
for my $animal (keys %h) {
for my $k (@{$h{$animal}}) {
if($k eq $keyword) {
say "$keyword $animal";
next KEYWORD;
}
}
}
say "keyword $keyword not found";
}
Чтобы критиковать мой собственный ответ: структура части, которая выполняет поиск, могла бы быть лучше. И, возможно, бессмысленно даже использовать упорядоченный хеш, поскольку поиск осуществляется по линейному списку. Может быть, это должен быть массив массивов
use strict;
use warnings;
use Tie::IxHash;
#open file
open(my $fh,"ani.txt") ||die $!;
#make an ordered hash
tie my %sizes, 'Tie::IxHash';
#read file into hash of arrays
while(<$fh>) {
(my $animal,my $size)=split(/\s+/);
if (!exists($sizes{$animal})) {
$sizes{$animal} = [$size];
} else {
push @{$sizes{$animal}},$size;
}
}
my $keyword="Little";
my $running=1;
my $depth=0;
while( $running ) {
$running = 0;
for my $search (keys %sizes) {
next if ($depth > @{$sizes{$search}});
$running = 1;
if ($keyword eq $sizes{$search}[$depth]) {
print "FOUND!!!!!! $search $depth";
exit(0);
}
}
$depth++;
}
Вот еще один вариант решения заявленной проблемы. Чтобы решить данную проблему, нет необходимости хранить что-либо, кроме первого ключа "size" для каждого животного в хэше.
Затем этот хэш можно использовать для поиска животного
use strict;
use warnings;
open(my $fh,"ani.txt") ||die $!;
my %animals;
#read file into hash
while(<$fh>) {
(my $animal,my $size)=split(/\s+/);
#only add the animal the first time the size is found
if (!exists($animals{$size})) {
$animals{$size} = $animal;
}
}
my $keyword="Little";
print "animal is ", $animals{$keyword};