Maverick
Maverick

Reputation: 587

How to use a key in hash for a value for another key

I have one hash there I have two key, I want to use one key as a value of another key. Is it possible in Perl?

exp:

%hash= (
        abs =>[a,b,c,e];
        xyz=> abs
      );

I tried but was not able to do this.

Upvotes: 2

Views: 527

Answers (5)

TLP
TLP

Reputation: 67900

You can use whatever value you wish as a hash value, including the name of another key. You can not, however, fail to quote the value, as it is not automagically quoted like the keys:

my %hash = (
    abs => 'foo',
    xyz => 'abs'
);

Quoting a parameter preceeding => is optional, if it does not contain spaces. Quoting the parameter following it is not.

You might also be interested to know that

[a,b,c,d]

will produce warnings, if you have warnings turned on (which you always should).

Unquoted string "a" may clash with future reserved word at
Unquoted string "b" may clash with future reserved word at

The reason this still "works" is -- as far as I know -- for backwards compatibility, and you should always quote your strings. Furthermore, case in point, your bareword abs is actually mistaken for the built-in function abs, which in this case will try to find the absolute value of $_, and probably fail, returning 0 (and issuing a warning about undefined value in $_).

What your array ref should look like is this:

['a', 'b', 'c', 'd']

Or with a simpler syntax, using the qw() operator:

[ qw(a b c d) ]

You might also note that semi-colon ; is not a valid character inside an assignment to a hash. The key/value pairs inside the parentheses shall be delimited with commas, nothing else.

Upvotes: 2

chepner
chepner

Reputation: 530853

One problem is that while the hash is being defined, it is anonymous. Not until the entire list is parsed is it assigned to %hash, so there's really no way to reference earlier parts of the hash while it is being defined. There are a couple of workarounds available:

my $common_lref = ['a', 'b', 'c', 'e'];
my %hash = ( abs => $common_lref, xyz => $common_lref );

or

my %hash = ( abs => ['a', 'b', 'c', 'e'] );
$hash{xyz} = $hash{abs};

In both cases, changing the array referenced by $hash{abs} changes $hash{xyz}, and vice versa.

Note: This only works if the value is a reference (as it is here), and only it only works as long as you don't change $hash{abs} or $hash{xyz}. You can still change the elements of the array referenced by $hash{abs} and $hash{xyz} (including adding and deleting elements).

Upvotes: 1

chrsblck
chrsblck

Reputation: 4088

This code doesn't compile.

Here's a working example:

#!/usr/bin/perl

use strict; 
use warnings;

my %hash = ( 
        abs => ['a', 'b','c','e'],
        xyz=> 'abs'
      );

print "abs: @{ $hash{$hash{xyz}} }\n";

First, use use warnings; use strict;

You have to quote your value at xyz =>. Side note: abs is also a perl built-in.

You also need to quote your anonymous array value at abs =>:

Eg, `[ qw(a b c) ]` or `['a', 'b', 'c',]`. 

Then in the print, I dereference(@{}) the value, as it is a list.

Upvotes: 0

pavel
pavel

Reputation: 3498

First, always use

use strict;
use warnings;

then, this should work:

my %hash = (
    abs => [ qw(a b c) ],
    xyz => 'abs',
);

print $hash{ $hash{xyz} }[0];

# prints 'a'

Upvotes: 1

dlaehnemann
dlaehnemann

Reputation: 701

You are simply using a wrong syntax. Try this instead:

#!/usr/bin/env perl

# warnings and strict are ALWAYS a good idea in perl code
use warnings;
use strict;

my %hash = ( 
        abs => ['a', 'b','c','e'], # make strings clear and use a comma, no semicolon
        xyz => 'abs'
);

And if you want your hash printed out, just to check it, Data::Dumper is useful - especially once you have a bigger hash:

use Data::Dumper;
print Dumper(\%hash);

Upvotes: 2

Related Questions