построение хеша из строки - PullRequest
       21

построение хеша из строки

1 голос
/ 31 октября 2011

У меня есть следующая строка на 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?

Ответы [ 4 ]

4 голосов
/ 31 октября 2011
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 голос
/ 31 октября 2011

Drats: у вас есть повторяющиеся клавиши ... Я хотел что-то сделать с map или grep.

Это довольно просто понять:

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} было ссылкой намассив из одного члена.Это правильно?

1 голос
/ 31 октября 2011

Если вы хотите, чтобы множественные значения для одного и того же ключа были ссылкой на массив, то один из способов сделать это выглядит так:

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'
               ]
    };
0 голосов
/ 31 октября 2011

Вероятно, самый простой (стандартный) способ сделать это - 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' );
...