Re: setting hash keys by array
by japhy (Canon) on Sep 09, 2002 at 16:27 UTC
|
Here's how I usually do it:
use Data::Dumper;
my @keys = qw( this that those );
my $node = \\my %hash;
# edit: this was my old way...
# my $i = 0;
# $node = \$$node->{$keys[$i++]} while $i < @keys;
# thanks to Juerd
$node = \$$node->{$_} for @keys;
$$node = "value";
print Dumper \%hash;
_____________________________________________________
Jeff[japhy]Pinyan:
Perl,
regex,
and perl
hacker, who'd like a job (NYC-area)
s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??; | [reply] [d/l] |
|
$node = \$$node->{$keys[$i++]} while $i < @keys;
++. IMHO, this is the only sane approach. But why not $node = \$$node->{$_} for @keys;?
Update
Reputation: 41, it says. MADNESS. I only suggested the use of for LIST instead of explicitly using an index variable. It's a style related comment. Why on earth did you people upvote this THIS MUCH? There are better nodes getting lower scores. Vote for those. ++ japhy, ++ demerphq for they did the work. I only complained about style.
- Yes, I reinvent wheels.
- Spam: Visit eurotraQ.
| [reply] [d/l] |
|
use Data::Dumper;
my @keys = qw( this that those );
my $node='value';
$node={$_=>$node} foreach reverse @keys;
print Dumper $node;
__END__
$VAR1 = {
'this' => {
'that' => {
'those' => 'value'
}
}
};
--- demerphq
my friends call me, usually because I'm late....
| [reply] [d/l] |
|
my @chain = qw/a b c d/;
my %hash;
sub foo(\%@){
local $_ = shift;
$_ = $_->{scalar shift} = {} while @_;
}
foo %hash => @chain;
? it's becoming obfuscated ...
--
http://fruiture.de | [reply] [d/l] |
|
My mistake -- I lifted it from old code of mine. Recent versions use your suggested alteration.
_____________________________________________________
Jeff[japhy]Pinyan:
Perl,
regex,
and perl
hacker, who'd like a job (NYC-area)
s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;
| [reply] |
|
Thanks for your answer !!, but can you give me a little explenation, what exactly it does and the syntax (especially lines 3)
1) use Data::Dumper;
2) my @keys = qw( this that those );
3) my $node = \\my %hash;
4) $node = \$$node->{$_} for @keys;
5) $$node = "value";
6) print Dumper \%hash;
I prefer understanding this before using it.
Thanks
Hotshot | [reply] [d/l] |
|
Yeah this is a nasty cryptic and totally groovy way to do things. I think I understand how it works, let see if I am right...
my $node=\\my %hash;
This sets $node to be a reference to a reference to %hash.
$node = \$$node->{$_} for @keys;
So this says to make node become equal to a reference to the slot $_ in the current hashref that $node references (foreach element in the list). It might be clearer to write it like so:
$node = \(${$node}->{$_})
Basically the idea of this is to take advantage of perls autovivification. The double reference is a nice way to ensure that we are always pointed at the slot that holds the previous key. If that value is undef, then it will be autovivified when it is used as a reference.
$$node = "value";
Stick the final value in.
Cool eh? juerd++ and japhy++
--- demerphq
my friends call me, usually because I'm late....
| [reply] [d/l] [select] |
|
Here's how I usually do it:
Is this something that you usually need to do? :P
-Lee
"To be civilized is to deny one's nature."
| [reply] |
|
Har har. First, you misunderstand my sentence. Second, it's done more often than you might think. I have a friend at RiskGrades who asked for some help setting up a hash in this way. She gets a list of keys, and needs to build up a hash (of hashes)+ based on those keys.
_____________________________________________________
Jeff[japhy]Pinyan:
Perl,
regex,
and perl
hacker, who'd like a job (NYC-area)
s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;
| [reply] |
|
Re: setting hash keys by array
by broquaint (Abbot) on Sep 09, 2002 at 16:16 UTC
|
This seems to do the trick
use Data::Dumper;
my @a = split ' ', q[foo bar baz quux];
my $le = my $h = {};
for(0 .. $#a - 1) {
$le->{ $a[$_] } = { $a[$_ + 1] => {} };
$le = $le->{ $a[$_] };
}
print Dumper $h;
__output__
$VAR1 = {
'foo' => {
'bar' => {
'baz' => {
'quux' => {}
}
}
}
};
Although are you sure this is the trick you want to be performing?
HTH
_________ broquaint | [reply] [d/l] |
Re: setting hash keys by array
by blssu (Pilgrim) on Sep 09, 2002 at 17:31 UTC
|
sub nested {
return ( shift, (@_) ? { nested(@_) } : 1 )
}
my %hash = nested(qw(red green brown));
| [reply] [d/l] |
Re: setting hash keys by array
by Aristotle (Chancellor) on Sep 09, 2002 at 17:05 UTC
|
my @array = qw(red green brown);
my %hash;
my $ptr = \%hash;
$ptr = $ptr->{$_} = {} for @array;
$ptr = 1;
Makeshifts last the longest. | [reply] [d/l] |
|
That code (and several other examples) don't work quite like the request:
$hash{red}{green}{brown} = 1
They do this instead:
$hash{red}{green}{brown} = { }
That inner-most key makes a lot of the foreach solutions kind of ugly because the last key must be treated specially -- unless there's a way to transmogrify a hash ref into a scalar ref? Here's a short reverse foreach that uses globs to solve the corner case:
my @array = qw(red green brown);
use vars qw(%hash);
foreach (reverse @array) {
*hash = { $_ => (%hash) ? \%hash : 1 }
}
The lexical version is more ugly and a lot less efficient:
my @array = qw(red green brown);
my %hash;
foreach (reverse @array) {
%hash = ( $_ => (%hash) ? { %hash } : 1 )
}
| [reply] [d/l] [select] |
|
They do this instead:
$hash{red}{green}{brown} = { }
True, that's what comes out of the for loop. Then the next instruction in my sample turns it into the requested result.. Is the following more to your liking?
my $ptr = \%hash;
$ptr = $ptr->{$_} = {} for @array[0..$#array-1]; # fixed; s/shift @arr
+ay/$_/
$ptr->{$array[-1]} = 1;
or maybe
my $ptr = \%hash;
$ptr = $ptr->{shift @array} = {} while @array > 1;
$ptr->{$array[0]} = 1;
Update: forgot to remove the shift when I initially copypasted. See comment.
Makeshifts last the longest. | [reply] [d/l] [select] |
|
|
Re: setting hash keys by array
by Shendal (Hermit) on Sep 09, 2002 at 16:13 UTC
|
How about something like this?
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
my @ary = qw(red green brown);
my %hash = ();
eval '$hash{' . join('}{',@ary) . '}++;';
print Dumper(\%hash);
That prints:
$VAR1 = {
'red' => {
'green' => {
'brown' => '1'
}
}
};
Cheers,
Shendal
| [reply] [d/l] [select] |
|
| [reply] |
Re: setting hash keys by array
by shotgunefx (Parson) on Sep 09, 2002 at 16:09 UTC
|
What you've specified is a hash of a hash of a hash. I don't think that's what you meant. If you meant each array value ends in a single hash with a value of 1, the below will work.
my @array =(a..f);
my %h = map { $_ => 1 } @array;
-Lee
"To be civilized is to deny one's nature." | [reply] [d/l] |
Re: setting hash keys by array
by boo_radley (Parson) on Sep 09, 2002 at 16:14 UTC
|
my @foo = qw (brown green red);
$e .= "{$_}" foreach @foo;
$e= "\$bar$e=1";
eval $e;
| [reply] [d/l] |
Re: setting hash keys by array
by artist (Parson) on Sep 09, 2002 at 16:25 UTC
|
| [reply] |
Re: setting hash keys by array
by Chmrr (Vicar) on Sep 10, 2002 at 01:45 UTC
|
See Re: descending a tree of hash references for a discussion of the same problem. Most of the solutions in this thread are handy, but sometimes it's useful to be able to wrap it into a subroutine.
perl -pe '"I lo*`+$^X$\"$]!$/"=~m%(.*)%s;$_=$1;y^`+*^e v^#$&V"+@( NO CARRIER'
| [reply] |
Re: setting hash keys by array
by the_slycer (Chaplain) on Sep 09, 2002 at 16:10 UTC
|
$hash{$_}++ foreach @array
Update:
Misunderstood the question. Ignore me :P | [reply] |
Re: setting hash keys by array
by Felonious (Chaplain) on Sep 10, 2002 at 14:46 UTC
|
my @arr = qw(red green brown);
my $hash;
$hash = { $_ => $hash || 1 } for (reverse @arr);
-- O thievish Night, Why should'st thou, but for some felonious end, In thy dark lantern thus close up the stars? --Milton | [reply] [d/l] |
Re: setting hash keys by array
by Anonymous Monk on Sep 10, 2002 at 15:56 UTC
|
| [reply] |