2011-10-30 72 views
1

我对perl的以下字符串建立一个哈希:从字符串

my $string = xyz;1;xyz;2;a;2;b;2 

我想这个字符串像下面后建立一个哈希:

my @array =split /;/,$string; 

$hash{xyz} =(1,2); 
$hash{b}=(2); 
$hahs{a}=(2); 

什么是Perl方式做这个?

+1

如果你没有有重复的键,这将是微不足道的:'我的%散列=拆分/; /,$字符串;' –

回答

4
my $string = "xyz;1;xyz;2;a;2;b;2"; 
my %hash; 
push @{$hash{$1}}, $2 while $string =~ s/^(\w+);(\d+);?//g; 

其实

push @{$hash{$1}}, $2 while $string =~ m/(\w+);(\d+);?/g; 

效果会更好,因为这不会吃了你原来的字符串。

1

假设你想要的多个值相同的键是一个数组引用,然后做一个方式,它是这样的:

my @values = split /;/, $string; 

my %hash; 
while(@values) { 
    my $key = shift @values; 
    my $val = shift @values; 

    if (exists $hash{$key} && !ref $hash{$key}) { 
     # upgrade to arrayref 
     $hash{$key} = [ $hash{$key}, $val ]; 
    } elsif (ref $hash{$key}) { 
     push @{ $hash{$key} }, $val; 
    } else { 
     $hash{$key} = $val; 
    } 
} 

与您的数据,这会导致类似

结构
{ 
     'a' => '2', 
     'b' => '2', 
     'xyz' => [ 
       '1', 
       '2' 
       ] 
    }; 
1

Drats:你有重复键...我想用mapgrep做点什么。

这是相当简单的理解:

my $string = "xyz;1;xyz;2;a;2;b;2"; 
my @array = split /;/ => $string; 

my %hash; 
while (@array) { 
    my ($key, $value) = splice @array, 0, 2; 
    $hash{$key} = [] if not exists $hash{$key}; 
    push @{$hash{$key}}, $value; 
} 

这一计划将工作,即使关键是不能在一起在你的字符串。例如,下面的工作即使xyz由其他值对分离:

my $string = "xyz;1;a;2;b;2;xyz;2"; 

我假设$hash{b}=(2);意味着你要的$hash{b}值设定为到单个构件数组的引用。那是对的吗?

+2

你实际上不需要行$ hash {$ key} = []如果不存在$ hash {$ key };'在所有。当你将第一个值推到它上面时,Perl会为你提供[autovivify](http://en.wikipedia.org/wiki/Autovivification)arrayref。 –

+2

另外,你可以做'my($ key,$ value)= splice @array,0,2;'而不是两个'shift's。哦,和IMO的“分裂”;“'是误导,应该避免:'split'的第一个参数是一个正则表达式(除了'split'的特殊魔术情况''),即使你把它写成一个字符串。 –

+0

我改变了'split'。这可能会产生误导。我也改变了拼接的双重转变。但是,我一直在将散列设置为空数组引用。它同时记录了我希望散列值是什么(对数组的引用),并且如果我输入错误的第一个值,它可以防止我意外地将其设置为散列引用。 –

0

也许最简单的(标准)的方式来做到这一点是List::MoreUtils::natatime

use List::MoreUtils qw<natatime>; 
my $iter = natatime 2 => split /;/, 'xyz;1;xyz;2;a;2;b;2'; 
my %hash; 
while (my ($k, $v) = $iter->()) { 
    push @{ $hash{ $k } }, $v; 
} 

但是抽象出来,我可能会想这样做的部分...

use List::MoreUtils qw<natatime>; 

sub pairs { 
    my $iter = natatime 2 => @_; 
    my @pairs; 
    while (my ($k, $v) = $iter->()) { 
     push @pairs, [ $k, $v ]; 
    } 
    return @pairs; 
} 

sub multi_hash { 
    my %h; 
    push @{ $h{ $_->[0] } }, $_->[1] foreach &pairs; 
    return wantarray ? %h : \%h; 
} 

my %hash = multi_hash(split /;/, 'xyz;1;xyz;2;a;2;b;2');