2014-01-06 3 views
3

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

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

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' 
} 
) 
+0

Что происходит, когда вы запускаете его? – Gabs00

+0

В вашей ожидаемой структуре данных нет массива. Это верно? – ikegami

ответ

6

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

%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]; 
} 

Благодаря autovivification, которые будут автоматически создавать хэши и массивы по мере необходимости.

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

for my $k1 (keys(%hash)) { 
    for my $k2 (keys(${ $hash{$k1} })) { 
     $hash{$k1}{$k2} = join(',', @{ $hash{$k1}{$k2} }); 
    } 
} 
+0

Отлично. Спасибо – Mdhale

+0

На самом деле, я думаю, что эти 'for' петли в конце - это идеальное место для использования' values' вместо 'keys'. 'для my $ v (значения% hash) {для my $ v (значения% $ v) {$ v = join ',', @ $ v}}' –

2

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

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

Давайте сделаем хэш, содержащий людей. Хэш будет содержать данные и будет определяться именем человека. Мы назовем это %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:, я предполагаю, что для этого человека будут следующие данные. У человека могут быть адреса и номера телефонов. Я буду хранить их в виде массивов под правильным хешем.

Как заявили ikegami, у Perl есть то, что называется auto vivification, который позволяет 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' 
            ] 
        } 
     }; 
+0

Если у меня есть еще один хэш хэшей с размером массива. Для примера выше допустим, что у меня есть тот же человек, но номер телефона и адрес разные. Я сохранил эту новую информацию. в хэшах хэшей с величиной массива, равной первой. Как я могу заменить адрес и номер телефона от первого до второго хэша хэшей со значением массива? – Raj

Смежные вопросы