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};
Другие вопросы по тегам