使用Perl在哈希散列中的一个键中存储多个值

时间:2012-01-03 11:31:53

标签: perl hash reference perl-data-structures

我正在尝试创建一个数据结构来存储我从数据库中删除的数据:

$Interaction{$TrGene}={
CisGene => $CisGene,
E => $e,
Q => $q,};

单个$ TrGene与许多CisGenes(具有唯一的E& Q)相关联。 e.g:

TrGene1 CisGene1 Q1 E2

TrGene1 CisGene2 Q2 E3

最后一个TrGene1会覆盖它之前的那些。我认为我需要创建对数组的引用,但在阅读此网页后,请不要完全理解如何执行此操作:http://perldoc.perl.org/perlreftut.html

我试图在该网页上使用国家/城市示例,但效果不是很好:

$Interaction{$TrGene}={
CisGene => $CisGene,
E => $e,
Q => $q,};
push @{$Interaction{$TrGene}}, $CisGene;

我收到错误'不是ARRAY ref'。我也只在那里使用了$ CisGene,但它不需要覆盖E&该CisGene的Q值。 (这个哈希知道CisGene是否与特定的E和Q相关联,或者我是否需要为此创建另一层哈希?)

由于

3 个答案:

答案 0 :(得分:3)

您的代码,但正确缩进以便可读。

$Interaction{$TrGene} = {
    CisGene => $CisGene,
    E       => $e,
    Q       => $q,
};
push @{$Interaction{$TrGene}}, $CisGene;

代码解释:

使用大括号{}将键值对列表分配给匿名哈希,并将该哈希引用分配给$TrGene哈希中的%Interaction键。然后尝试使用@{ ... }将其作为数组引用使用,这不起作用。

如果输入具有不同值的哈希键,则会覆盖它们。让我们来看一些实际的例子,它真的很容易

$Interaction{'foobar'} = {
    CisGene => 'Secret code',
    E       => 'xxx',
    Q       => 'yyy',
};

现在,您已在密钥'foobar'下存储了哈希引用。该哈希实际上是对数据结构的独立引用。如果您将它们视为标量,我认为跟踪结构会更容易:哈希(或数组)只能包含标量。

哈希%Interaction可能包含许多键,如果您输入了上述数据,则所有值都将是哈希引用。 E.g:

$hash1 = {  # note: curly brackets denote an anonymous hash 
    CisGene => 'Secret code',
    E       => 'xxx',
    Q       => 'yyy',
};
$hash2 = {
    CisGene => 'some other value',
    E       => 'foo',
    Q       => 'bar',
};

%Interaction = ( # note: regular parenthesis denote a list
    'foobar'   => $hash1,  # e.g. CisGene => 'Secret code', ... etc. from above
    'barbar'   => $hash2   # e.g. other key value pairs surrounded by {}
    ...
);

$hash1$hash2中包含的值类型现在是引用,是内存中数据的地址。如果您将其打印出来print $hash1,您会看到HASH(0x398a64)之类的内容。

现在,如果您使用现有密钥在%Interaction中输入新值,则该密钥将被覆盖。因为哈希键只能包含一个值:标量。在我们的例子中,是对哈希的引用。

您在示例中尝试使用'foobar'键的值作为数组引用(这很愚蠢,因为正如您现在可以看到的那样,它是一个哈希引用):

push @{$Interaction{$TrGene}}, $CisGene;

改写为:

push @{  $hash1  }, 'Secret code';  # using the sample values from above

不......那不起作用。

您需要的是一个新容器。我们将键'foobar'的值改为数组引用:

%Interaction = (
    'foobar'   => $array1,
    ...
);

其中:

$array1 = [ $hash1, $hash2 ];

$array1 = [       # note the square brackets to create anonymous array
              {   # curly brackets for anonymous hash
                  CisGene => 'Secret code',
                  E       => 'xxx',
                  Q       => 'yyy',
              },  # comma sign to separate array elements
              {   # start a new hash
                  CisGene => 'Some other value',
                  E       => 'foo',
                  Q       => 'bar',
              }   # end 
           ];     # end of $array1

现在,这完全是一种放置东西的麻烦方式,所以让我们更简单:

$CisGene = 'foobar';
$e = 'xxx';
$q = 'yyy';

my $hash1 = {
        CisGene => $CisGene,
        E       => $e,
        Q       => $q,
};

push @{$Interaction{$TrGene}}, $hash1;

或者您可以取消临时变量$hash1并直接指定它:

push @{$Interaction{$TrGene}}, {
    CisGene => $CisGene,
    E       => $e,
    Q       => $q,
};

访问元素时:

for my $key (keys %Interaction) {  # lists the $TrGene keys 
    my $aref = $Interaction{$key}; # the array reference
    for my $hashref (@$aref) {     # extract hash references, e.g. $hash1
        my $CisGene = $hashref->{'CisGene'};
        my $e       = $hashref->{'E'};
        my $q       = $hashref->{'Q'};
    }
}

注意直接处理引用时使用箭头运算符。您也可以说$$hashref{'CisGene'}

或直接:

my $CisGene = $Interaction{'foobar'}[0]{'CisGene'};

我建议阅读perldata。一个非常方便的模块是Data::Dumper。如果你这样做:

use Data::Dumper;
print Dumper \%Interaction; # note the backslash, Dumper wants references

它将为您打印出您的数据结构,这使您可以很容易地看到自己在做什么。请注意使用括号和大括号来表示数组和散列。

答案 1 :(得分:2)

这样的东西
push @{ $Interaction{ $TrGene }{members} }, $CisGene;

应该有用。

$Interaction{$TrGene}不能是数组引用,因为您只是为它分配了一个哈希引用。

当然,如果您想要EQ的组合(我会假设它在$TrGene键中指示,或者您是可能会造成更多混乱。)你会想要更像这样的东西:

 $Interaction{ $TrGene } //= { E => $e, Q => $q };
 push @{ $Interaction{ $TrGene }{CisGenes} }, $CisGene;

如果EQ取决于$TrGene的值,那么您将获得所需的分组。否则,您可以按如下方式考虑它们的下标:

push @{ $Interaction{ $e }{ $q } }, $CisGene;

并获得EQ$CisGene之间更大关联的映射。

答案 2 :(得分:2)

你差点把它放在你试图推入arrayref的地方。问题是您已经为$Interaction[$TrGene}分配了一个hashref,然后尝试将其用作@{ $Interaction{$TrGene} }的arrayref。

@{ $Interaction{$TrGene} }表示:

  • 您正在使用哈希值$Interaction{$TrGene}
  • 然后您取消引用数组@{ ... }。例如。你可以这样做:@array = @{$Interaction{$TrGene}}
  • 如果$Interaction{$TrGene}中没有值,则会在该点自动创建arrayref(称为自动生存)。

因此,假设您已经创建了这些hashref:

my $CisGene1 = {
    CisGene => 'CisGene1',
    E => 'E1',
    Q => 'Q1',
};
my $CisGene2 = {
    CisGene => 'CisGene2',
    E => 'E3',
    Q => 'Q2',
};

您可以将每个推送到您的arrayref:

push @{ $Interaction{$TrGene} }, $CisGene1, $CisGene2;