具有数组值的哈希哈希值

时间:2014-01-06 19:19:14

标签: perl perl-data-structures

我正在尝试使用具有数组值概念的哈希散列来生成哈希。我不确定我的语法是否正确。

下面是我希望应该创建带有数组值的哈希哈希值的代码部分。

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

2 个答案:

答案 0 :(得分: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];
}

由于自动更新,它将根据需要自动创建哈希和数组。

如果你真的想要字符串而不是数组,那么之后你总是可以使用join ','

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

答案 1 :(得分:2)

如果您正在使用push,则不应使用等号(除非您希望推送的项目数量)。那告诉我那里有一个问题。您可能对您的结构感到有些困惑。您要么将数据推送到数组引用中,要么就是要加入项目并将其推送到另一个结构中。你所写的内容有点难以理解,因为语法很难理解。

看起来你想要玩弄参考文献,看看你是否能掌握它们。当您处理这样的复杂结构时,如果您有一些......呃...... 真实世界数据,它会更容易理解。让我们创建一个数组哈希的真实世界哈希,这将更容易跟踪。

让我们制作一个包含人物的哈希。哈希将包含数据,并将由该人的姓名键入。我们称之为%people。我们的哈希,鲍勃和珍妮特将有两个人。鲍勃和珍妮特有各种地址和电话号码。我们将在哈希中有一个引用,其中包含名为PHONEADDRESS的数据字段的名称。

$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}包含对其他哈希的引用,而不仅仅是标量数据。

接下来,Bob和Janet可能有多个地址和电话号码,因此我们不会存储一个电话号码,而是$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'
                                    ]
                    }
        };