Re: Assign (key, value) to a hash w/o clobbering hash
by davorg (Chancellor) on Sep 28, 2006 at 08:23 UTC
|
%hash = (%hash, split /X/ 'fooXbar');
I don't think that's particularly efficient tho' as it rewrites the entire hash every time. I'd probably use your second solution and split to an intermediate array.
--
< http://dave.org.uk>
"The first rule of Perl club is you do not talk about
Perl club." -- Chip Salzenberg
| [reply] [d/l] |
|
|
To avoid this inefficiency, you could always tie your own hash which didn't clobber the original values, by not implementing CLEAR. So your above line becomes.
%hash = split /X/, 'fooXbar' # added the missing comma ;)
depends how far you want to go. Full example as follows... (BTW I did try to do this with Tie::StdHash, but couldn't figure it out)
#!/usr/bin/perl
use strict;
use Data::Dumper;
tie my %hash, 'ExpandingHash';
$hash{'still'} = 'here';
%hash = split /X/, 'fooXbar';
print Dumper(\%hash);
# I also added a new clear method, which you could use like this.
# tied(%hash)->FORCE_CLEAR;
__OUTPUT__
$VAR1 = {
'foo' => 'bar',
'still' => 'here'
};
#==================================================================
package ExpandingHash;
use strict;
sub TIEHASH { my %self; bless \%self, shift }
sub FETCH { $_[0]->{$_[1]} }
sub STORE { $_[0]->{$_[1]} = $_[2] }
sub FIRSTKEY { each %{$_[0]} }
sub NEXTKEY { each %{$_[0]} }
sub CLEAR { } # NOT IMPLEMENTED
sub DELETE { delete $_[0]->{$_[1]} }
sub EXISTS { exists $_[0]->{$_[1]} }
sub FORCE_CLEAR { %{$_[0]} = () }
---
my name's not Keith, and I'm not reasonable.
| [reply] [d/l] [select] |
|
|
package Tie::Hash::ExpandingHash;
use strict;
use warnings;
use Tie::Hash;
our @ISA = 'Tie::StdHash';
sub CLEAR { } # NOT IMPLEMENTED
sub FORCE_CLEAR { %{$_[0]} = () }
--
< http://dave.org.uk>
"The first rule of Perl club is you do not talk about
Perl club." -- Chip Salzenberg
| [reply] [d/l] |
|
|
Re: Assign (key, value) to a hash w/o clobbering hash
by Corion (Patriarch) on Sep 28, 2006 at 08:23 UTC
|
When merging two hashes, I mostly recreate the merged hash from the two other hashes:
my %actual = (%defaults,%args);
The order of %hash1 and %hash2 determines, which keys/values take precedence - most times, I want the defaults to have lower precedence than the supplied parameters. Of course, here, clobbering is what is wanted. I'm not aware of a callback-based solution to merge hashes like reduce does for lists. | [reply] [d/l] [select] |
Re: Assign (key, value) to a hash w/o clobbering hash
by johngg (Canon) on Sep 28, 2006 at 08:53 UTC
|
You can set the hash up at the beginning from multiple strings using map.
perl -e '%h = map{split /X/} q{fooXbar}, q{bishXbash};
print qq{$_ -> $h{$_}\n} for jeys %h;'
produces
bish -> bash
foo -> bar
If you have to add another key/value pair subsequently you will have to use intermediate variables to avoid the clobber. Cheers, JohnGG | [reply] [d/l] [select] |
Re: Assign (key, value) to a hash w/o clobbering hash
by cdarke (Prior) on Sep 28, 2006 at 09:57 UTC
|
The second solution gets my vote, but if you are worried about the extra array, just make it a 'my' variable inside a set of braces. If you are doing this several time in your code:
sub add2hash {
my ($value, $hashref) = @_;
my @array = (split /X/, $value);
$hashref->{$array[0]} = $array[1];
}
...
add2hash ('fooXbar', \%hash);
add2hash ('bishXbash', \%hash);
OK, possibly a sledge hammer to crack a nut, depends on how many time you are doing it.
update: corrected missing $ | [reply] [d/l] |
Re: Assign (key, value) to a hash w/o clobbering hash
by rjray (Chaplain) on Sep 28, 2006 at 08:34 UTC
|
@X_delimited_strings = qw(fooXbar bishXbash);
for (@X_delimited_strings)
{
@_ = split /X/;
$hash{$_[0]} = $_[1];
}
You will have to accept a temp variable somewhere. You can use those already available to you (like $_ and @_) or declare your own.
| [reply] [d/l] |
Re: Assign (key, value) to a hash w/o clobbering hash
by ikegami (Patriarch) on Sep 28, 2006 at 14:21 UTC
|
You can also use a hash slice.
%tmphash = map { split /X/ } "fooXbar", "bishXbash";
@hash{keys %tmphash} = values %tmphash;
| [reply] [d/l] |
Re: Assign (key, value) to a hash w/o clobbering hash
by jdporter (Paladin) on Sep 28, 2006 at 14:19 UTC
|
my $kv1 = 'fooXbar';
my $kv2 = 'bishXbash';
@hash{ keys %$_ } = values %$_
for { map { split /X/ } $kv1, $kv2 };
Don't be fooled by the for loop: it only iterates once; it's only there to avoid the explicit temporary variable (hash).
We're building the house of the future together.
| [reply] [d/l] [select] |
Re: Assign (key, value) to a hash w/o clobbering hash
by wazoox (Prior) on Sep 28, 2006 at 13:19 UTC
|
Why not using map? This is concise and uses no temporary variable :
%hash = map { split( /X/, $_ ) } ( "fooXbar","bishXbash") ;
# look Ma, that works!
foreach(keys %hash){
print "1: $_ = $hash{$_}\n";
}
| [reply] [d/l] [select] |
|
|
because the OP doesn't want to clobber what's already in the hash. Assigning a list to a hash clears out the hash first, and then starts assigning the new values.
Update: argh, see mreece's reply to this post
Regardless, the map is completely redundant here, the following two are equivalent.
%hash = map { split( /X/, $_ ) } ( "fooXbar","bishXbash");
%hash = split /X/, ("fooXbar","bishXbash");
---
my name's not Keith, and I'm not reasonable.
| [reply] [d/l] |
|
|
those are not at all equivalent!
DB<1> x %hash = map { split( /X/, $_ ) } ( "fooXbar","bishXbash");
0 'foo'
1 'bar'
2 'bish'
3 'bash'
DB<2> x %hash = split /X/, ("fooXbar","bishXbash");
0 'bish'
1 'bash'
| [reply] [d/l] |
|
|
# Works, but needs redundent array
undef %hash;
@array = (split /X/, "fooXbar");
$hash{$array[0]} = $array[1];
@array = (split /X/, "bishXbash");
$hash{$array[0]} = $array[1];
foreach(keys %hash){
print "2: $_ = $hash{$_}\n";
}
so what is to be achieved isn't that clear after all.
| [reply] [d/l] |
Re: Assign (key, value) to a hash w/o clobbering hash
by TedPride (Priest) on Sep 28, 2006 at 18:51 UTC
|
use Data::Dumper;
$hash{bing} = 'bang';
for (qw/fooXbar bishXbash/) {
@_ = split /X/, $_;
$hash{$_[0]} = $_[1];
}
print Dumper(\%hash);
| [reply] [d/l] |
Re: Assign (key, value) to a hash w/o clobbering hash
by Khen1950fx (Canon) on Sep 28, 2006 at 10:59 UTC
|
I gave your third approach a try. I tried this:
undef %hash
%hash = (%hash, split /X/ 'fooXbar');
%hash = (%hash, split /X/ 'bishXbash');
foreach(keys %hash) {
print "3: $_ = $hash{$_}\n";
}
It produced:
bish = bash
foo = bar
| [reply] [d/l] [select] |