Хеши хэшей со значениями массива

Я пытаюсь сгенерировать хеш, используя хэши хэшей с концепцией значений массива. Я не уверен, что мой синтаксис правильный.

Ниже приведен раздел кода, который, как я надеюсь, должен создавать хэши хэшей со значениями массива.

 use strict;
 %hash=();
 open IN, "samplefile.txt" or die "cannot open file:$!"; 
 while(<IN>){
     chomp $_;
     my @split=split("\t", $_);
     $hash{$split[0]}{$split[1]}=push @{ $hash{$split[0]}{$split[1]} },$split[2];
     push(@array, $split[1]);
  }

Пример набора данных:

4 10 2
9 4 3
4 3 2
4 3 8
4 10 5
4 5 2

Ожидаемый хэш.

%hash=(
    '4'=> {
    '10'=>'2, 5'
     '5' => '2'
     '3' => '2,8'
   }
 '9'=>{
     '4'=>'3'
 }
)

person Mdhale    schedule 06.01.2014    source источник
comment
Что происходит, когда вы запускаете его?   -  person Gabs00    schedule 06.01.2014
comment
В ожидаемой структуре данных нет массива. Это правильно?   -  person ikegami    schedule 06.01.2014


Ответы (2)


Я думаю, ты действительно хочешь

%hash = (
   '4' => {
      '10' => [ 2, 5 ],
      '5'  => [ 2 ],
      '3'  => [ 2, 8 ],
    },
    '9' => {
       '4' => [ 3 ],
    },
);

Решение:

my %hash;
while (<>) {
   my @F = split;
   push @{ $hash{ $F[0] }{ $F[1] } }, $F[2];
}

Благодаря автовивификации автоматически создаются хэши и массивы по мере необходимости.

Вы всегда можете использовать join ',' впоследствии, если вам действительно нужны строки вместо массивов.

for my $k1 (keys(%hash)) {
   for my $k2 (keys(${ $hash{$k1} })) {
      $hash{$k1}{$k2} = join(',', @{ $hash{$k1}{$k2} });
   }
}
person ikegami    schedule 06.01.2014
comment
На самом деле я думаю, что эти циклы for в конце — идеальное место для использования values вместо keys. for my $v (values %hash){ for my $v (values %$v){ $v = join ',', @$v }} - person Brad Gilbert; 14.01.2014

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

Похоже, вы хотите поиграть со ссылками и посмотреть, сможете ли вы их освоить. Когда вы имеете дело со сложными структурами, подобными этой, легче понять, если у вас есть какие-то... ммм... данные из реального мира. Давайте создадим реальный хэш хэша массивов, и его будет немного легче отслеживать.

Давайте сделаем хэш, содержащий людей. Хэш будет содержать данные и будет содержать имя человека. Мы назовем это %people. В нашем хеше будет два человека, Боб и Джанет. У Боба и Джанет разные адреса и номера телефонов. У нас будет ссылка на хэш, который будет содержать имена наших полей данных с именами PHONE и ADDRESS.

$people{Bob}->{ADDRESS};    # Bob's addresses
$people{Bob}->{PHONE};      # Bob's phone numbers
$people{Janet}->{ADDRESS};  # Janet's Addresses
$people{Janet}->{PHONE};    # Janet's Phone numbers

Обратите внимание на синтаксис стрелки. Это говорит вам, что $people{Bob} содержит ссылку на другой хэш, а не просто скалярные данные.

Далее, у Боба и Джанет может быть несколько адресов и телефонных номеров, поэтому вместо хранения одного телефонного номера у нас будет $people{Bob}->{PHONE} для хранения ссылки на массив телефонных номеров, а $people{Bob}->{ADDRESS} будет содержать ссылку на массив адресов.

Вот короткая программа, которая считывает данные. Каждый раз, когда строка начинается с person:, я предполагаю, что следующие данные будут для этого человека. У человека могут быть адреса и телефоны. Я буду хранить их в виде массивов под правильным хешем.

Как сказал Икегами, в Perl есть то, что называется авто-оживлением, что позволяет Perl точно определить, на какой тип ссылки вы указываете. Тем не менее, мне нравится заявлять, что я ожидаю от структуры данных для целей документации. Следующие операторы в моей программе на самом деле не нужны, но я нахожу их полезными:

$people{$person} = {};  # This is a reference to another array

и

if ( not exists $people{$person}->{ADDRESS} ) {
    $people{$person}->{ADDRESS} = [];  #This is a reference to an array
}

Вот моя программа:

#! /usr/bin/env perl
#
use strict;
use warnings;
use Data::Dumper;
use feature qw(say);

my %people;
my $person;
while ( my $line = <DATA> ) {
    chomp $line;
    my ( $type, $data ) = split /:\s*/, $line;
    if ( $type eq "person" ) {
        $person = $data;
        $people{$person} = {};  # This is a reference to another array
    }
    if ( $type eq "address" ) {
        if ( not exists $people{$person}->{ADDRESS} ) {
            $people{$person}->{ADDRESS} = [];  #This is a reference to an array
        }
        push @{ $people{$person}->{ADDRESS} }, $data;
    }
    if ( $type eq  "phone" ) {
        if ( not exists $people{$person}->{PHONE} ) {
            $people{$person}->{PHONE} = [];    #This is a reference to an array
        }
        push @{ $people{$person}->{PHONE} }, $data;
    }
}
say Dumper \%people;
__DATA__
person: Bob
address: 120 Main Street, Suburbville CO
address: 123 Wage Slave Lane, Industry CO
address: 1 Beach Hut Road, Getaway CA
phone: 555-1111
phone: 555-2222
person: Janet
address: 230 Oak Tree Road, Gloomsburg CO
address: 544 Initech Road, Businesstown CO
phone: 555-3333
phone: 555-4444

Это производит:

$VAR1 = {
        'Bob' => {
                    'PHONE' => [
                                '555-1111',
                                '555-2222'
                                ],
                    'ADDRESS' => [
                                    '120 Main Street, Suburbville CO',
                                    '123 Wage Slave Lane, Industry CO',
                                    '1 Beach Hut Road, Getaway CA'
                                ]
                },
        'Janet' => {
                    'PHONE' => [
                                    '555-3333',
                                    '555-4444'
                                ],
                    'ADDRESS' => [
                                    '230 Oak Tree Road, Gloomsburg CO',
                                    '544 Initech Road, Businesstown CO'
                                    ]
                    }
        };
person David W.    schedule 06.01.2014
comment
Если у меня есть другие хэши хэшей со значением массива. В приведенном выше примере допустим, что у меня тот же человек, но номер телефона и адрес разные. Я сохранил эту новую информацию. в хэшах хэшей со значением массива, таким же, как и первое. Как я могу заменить адрес и номер телефона с первого на второй хэши хэшей значением массива? - person Raj; 11.05.2016