Как я могу сделать массив значений после дублирования ключей в хэше? - PullRequest
0 голосов
/ 11 декабря 2018

У меня вопрос по поводу дубликатов ключей в хешах.Скажем, мой набор данных выглядит примерно так:

>Mammals
Cats
>Fish
Clownfish
>Birds
Parrots
>Mammals
Dogs
>Reptiles
Snakes
>Reptiles
Snakes

То, что я хотел бы получить из своего скрипта, это хеш, который выглядит так:

$VAR1 = {
          'Birds' => 'Parrots',
          'Mammals' => 'Dogs', 'Cats',
          'Fish' => 'Clownfish',
          'Reptiles' => 'Snakes'
        };

Я нашел здесь возможный ответ(https://www.perlmonks.org/?node_id=1116320). Однако я не уверен, как определить значения и дубликаты в формате моего набора данных.

Вот код, который я использовал:

use Data::Dumper;
    open($fh, "<", $file) || die "Could not open file $file $!/n";

    while (<$fh>) {
        chomp;
        if($_ =~ /^>(.+)/){
            $group = $1; 
            $animals{$group} = ""; 
            next;

        }
        $animals{$group} .= $_;   
push @{$group (keys %animals)}, $animals{$group};

    }
print  Dumper(\%animals);

Когда я ее выполняю, функция push не работает, так как выходные данные этой команды такие же, как и при отсутствии команды (в дублирующейся группе «Млекопитающее» она заменяет кошку собакой вместо того, чтобы обамассивы в пределах одной группы).

Любые предложения относительно того, что я делаю неправильно, будут высоко оценены.

Спасибо!

Ответы [ 2 ]

0 голосов
/ 11 декабря 2018

Дано:

__DATA__
>Mammals
Cats
>Fish
Clownfish
>Birds
Parrots
>Mammals
Dogs
>Reptiles
Snakes
>Reptiles
Snakes

(в конце исходного кода или файла с этим содержимым)

Если вы хотите slurp файл,вы можете сделать что-то с регулярным выражением и HoH, как это:

use Data::Dumper;
use warnings;
use strict;
my %animals;
my $s;

while(<DATA>){
    $s.=$_;
}    

while($s=~/^>(.*)\R(.*)/mg){
    ++$animals{$1}{$2};
}

print Dumper(\%animals);

Отпечатки:

$VAR1 = {
          'Mammals' => {
                         'Cats' => 1,
                         'Dogs' => 1
                       },
          'Birds' => {
                       'Parrots' => 1
                     },
          'Fish' => {
                      'Clownfish' => 1
                    },
          'Reptiles' => {
                          'Snakes' => 2
                        }
        };

Которые вы можете получить в свой формат с помощью этой полной программы Perl:

$s.=$_ while(<DATA>);
++$animals{$1}{$2} while($s=~/^>(.*)\R(.*)/mg);
while ((my $k, my $v) =  each (%animals)) {
    print "$k: ". join(", ", keys($v)) . "\n";
}

Отпечатки:

Fish: Clownfish
Birds: Parrots
Mammals: Cats, Dogs
Reptiles: Snakes

(Помните, что порядок вывода может отличаться от порядка файлов, поскольку хеши Perl не поддерживают порядок вставки ...)

0 голосов
/ 11 декабря 2018

Ты здесь очень близко.Мы не можем получить именно тот результат, который вы хотите получить от Data::Dumper, потому что хэши могут иметь только одно значение на ключ.Самый простой способ исправить это - присвоить ключу ссылку на массив и добавить к нему что-нибудь.Но так как вы также хотите исключить дубликаты, проще создать хеши в качестве промежуточного представления, а затем преобразовать их в массивы:

use Data::Dumper;
my $file = "animals.txt";
open($fh, "<", $file) || die "Could not open file $file $!/n";

while (<$fh>) {
    chomp;
    if(/^>(.+)/){
        $group = $1; 
        next;
    }
    $animals{$group} = {} unless exists $animals{$group};
    $animals{$group}->{$_} = 1;
}

# Transform the hashes to arrays
foreach my $group (keys %animals) {
  # Make the hash into an array of its keys
  $animals{$group} = [ sort keys %{$animals{$group}} ];
  # Throw away the array if we only have one thing
  $animals{$group} = $animals{$group}->[0] if @{ $animals{$group} } == 1;
}
print  Dumper(\%animals);

Результат равен

$VAR1 = {
          'Reptiles' => 'Snakes',
          'Fish' => 'Clownfish',
          'Birds' => 'Parrots',
          'Mammals' => [
                         'Cats',
                         'Dogs'
                       ]
        };

, который настолько близокпоскольку вы можете получить то, что у вас было в качестве желаемого результата.

Для простоты обработки загруженных данных, на самом деле может быть проще , а не выбрасывать массивы в случае с одним элементомтак что каждая запись в хэше может обрабатываться одинаково (все они являются ссылками на массивы, независимо от того, сколько в них вещей).В противном случае вы добавили условное выражение для удаления массивов, и вам необходимо добавить еще один условный тест в код обработки, чтобы проверить

if (ref $item) {
    # This is an anonymous array
} else {
    # This is just a single entry
}

, и проще иметь только один путь вместо двух, дажеесли else просто снова упаковывает один элемент в массив.Оставьте их как массивы (удалите строку $animals{$group} = $animals{$group}->[0]), и все будет в порядке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...