views:

59

answers:

4

In an earlier question I asked how to initialize a Perl hash using slices. It is done like this:

my %hash = ();
my @fields = ('currency_symbol', 'currency_name');
my @array = ('BRL','Real');
@hash{@fields} = @array;

Now let's imagine a more complex hash, and here is how it is initialized:

my %hash = ();
my $iso = 'BR';
$hash->{$iso}->{currency_symbol} = 'BRL';
$hash->{$iso}->{currency_name} = 'Real';
print Dumper($hash);

This results in the following:

$VAR1 = {
          'BR' => {
                    'currency_symbol' => 'BRL',
                    'currency_name' => 'Real'
                  }
        };

Now the question would be: how to initialize this particular hash using the splice method?

+1  A: 

First of all, since your hash is declared %hash, it would just be $hash{ $iso }. $hash->{ $iso } refers to a slot in the hash pointed to by $hash, which may or may not be pointing to %hash.

But once you have that, you can do the following:

@{ $hash{ $iso } }{ @fields } = qw<BRL Real>;

But as levels soon get complex, it's better to forgo the autovivification luxury and do the following:

my $h = $hash{ $iso }{blah}{blah} = {};
@$h{ @field_names } = @field_values;

Relocatable pointers within the hierarchy of hashes makes it easier to write anonymous accesses that also allow for easy slices.

Axeman
Thanks for the clarification.
emx
+2  A: 

The perllol documentation's Slices section covers array slices:

If you want to get at a slice (part of a row) in a multidimensional array, you're going to have to do some fancy subscripting. That's because while we have a nice synonym for single elements via the pointer arrow for dereferencing, no such convenience exists for slices. (Remember, of course, that you can always write a loop to do a slice operation.)

Here's how to do one operation using a loop. We'll assume an @AoA variable as before.

@part = ();
$x = 4;
for ($y = 7; $y < 13; $y++) {
  push @part, $AoA[$x][$y];
}

That same loop could be replaced with a slice operation:

@part = @{ $AoA[4] } [ 7..12 ];

Extrapolating to hash slices, we get

@{ $hash{$iso} }{@fields} = @array;

You know it's a hash slice because the “subscripts” are surrounded with curly braces rather than square brackets.

Greg Bacon
Thanks, this works! Great.
emx
@emx You're welcome! I'm glad it helps.
Greg Bacon
+1  A: 

$hash{$iso} is going to be a hash reference. You replace what would be the variable name (without the sigil) in a simple slice with a block containing the reference, so:

@array{@list}

becomes

@{ $hash{$iso} }{@list}

See http://perlmonks.org/?node=References+quick+reference

ysth
Yes, should have tried that indeed. Thanks for the pointer.
emx
A: 

Your looking for something like this ?

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

my %hash = ();
my $iso = 'BR';

@{$hash{$iso}}{qw(currency_symbol currency_name)} = qw(RBL Real);

print Dumper(\%hash);
Prix