Skip Menu |

This queue is for tickets about the Hash-Merge CPAN distribution.

Report information
The Basics
Id: 67328
Status: open
Priority: 0/
Queue: Hash-Merge

People
Owner: Nobody in particular
Requestors: SREZIC [...] cpan.org
Cc: srezic [...] iconmobile.com
AdminCc:

Bug Information
Severity: (no value)
Broken in: 0.12
Fixed in: (no value)



CC: srezic [...] iconmobile.com
Subject: "tiedness" of hashes not preserved
If two tied hashes are merged with Hash::Merge, then the tie property is not preserved in the merged hash. At least this should be mentioned in the documentation, but it's possible to specify a behavior to overcome this limitation. The trick is to not create a new result hash, but to merge into the existing left hash. See the attached script how this could work. Maybe something similar could go into the standard Hash-Merge distribution? Regards, Slaven
Subject: hash-merge-tie-ixhash.pl
#!/usr/bin/perl use strict; use Test::More 'no_plan'; use Hash::Merge 'merge'; use Tie::IxHash; { tie my %hash1, 'Tie::IxHash'; %hash1 = map { ($_ => $_) } (1..10); is join(" ", keys %hash1), join(" ", sort { $a <=> $b } keys %hash1), 'Keys are sorted'; my $merged = merge \%hash1, {}; local $TODO = "This does not work!"; is join(" ", keys %$merged), join(" ", sort { $a <=> $b } keys %$merged), 'Keys are still sorted after merge'; } { tie my %hash1, 'Tie::IxHash'; %hash1 = map { ($_ => $_) } (1..10); is join(" ", keys %hash1), join(" ", sort { $a <=> $b } keys %hash1), 'Keys are sorted'; my $m = new_merge_into(); $m->merge(\%hash1, {}); is join(" ", keys %hash1), join(" ", sort { $a <=> $b } keys %hash1), 'Keys are still sorted'; } { tie my %hash1, 'Tie::IxHash'; %hash1 = map { ($_ => $_) } (1..10); is join(" ", keys %hash1), join(" ", sort { $a <=> $b } keys %hash1), 'Keys are sorted'; tie my %hash2, 'Tie::IxHash'; %hash2 = map { ($_ => $_) } (11..20); my $m = new_merge_into(); $m->merge(\%hash1, \%hash2); is join(" ", keys %hash1), join(" ", sort { $a <=> $b } keys %hash1), 'Keys are still sorted'; } sub new_merge_into { my $m = Hash::Merge->new; $m->specify_behavior ({ # basically this is LEFT_PRECEDENT with the case HASH -> # HASH modified 'SCALAR' => { 'SCALAR' => sub { $_[0] }, 'ARRAY' => sub { $_[0] }, 'HASH' => sub { $_[0] }, }, 'ARRAY' => { 'SCALAR' => sub { [ @{ $_[0] }, $_[1] ] }, 'ARRAY' => sub { [ @{ $_[0] }, @{ $_[1] } ] }, 'HASH' => sub { [ @{ $_[0] }, values %{ $_[1] } ] }, }, 'HASH' => { 'SCALAR' => sub { $_[0] }, 'ARRAY' => sub { $_[0] }, 'HASH' => sub { _merge_into_hashes( $_[0], $_[1] ) }, }, }); $m; } sub _merge_into_hashes { my $self = &Hash::Merge::_get_obj; my ( $left, $right ) = ( shift, shift ); if ( ref $left ne 'HASH' || ref $right ne 'HASH' ) { die 'Arguments for _merge_hashes must be hash references'; } foreach my $leftkey ( keys %$left ) { if ( exists $right->{$leftkey} ) { $self->merge( $left->{$leftkey}, $right->{$leftkey} ); } } foreach my $rightkey ( keys %$right ) { if ( !exists $left->{$rightkey} ) { $left->{$rightkey} = $right->{$rightkey}; } } }
Subject: Re: [rt.cpan.org #67328] "tiedness" of hashes not preserved
Date: Fri, 8 Apr 2011 14:45:27 -0500
To: bug-Hash-Merge [...] rt.cpan.org
From: Dan Muey <webmaster [...] simplemood.com>
thanks, I'll incorporate this when I can, much appreciated! On Apr 8, 2011, at 3:29 AM, Slaven_Rezic via RT wrote: Show quoted text
> Fri Apr 08 04:29:58 2011: Request 67328 was acted upon. > Transaction: Ticket created by SREZIC > Queue: Hash-Merge > Subject: "tiedness" of hashes not preserved > Broken in: 0.12 > Severity: (no value) > Owner: Nobody > Requestors: SREZIC@cpan.org > Status: new > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=67328 > > > > If two tied hashes are merged with Hash::Merge, then the tie property is > not preserved in the merged hash. At least this should be mentioned in > the documentation, but it's possible to specify a behavior to overcome > this limitation. The trick is to not create a new result hash, but to > merge into the existing left hash. See the attached script how this > could work. Maybe something similar could go into the standard > Hash-Merge distribution? > > Regards, > Slaven > > #!/usr/bin/perl > > use strict; > use Test::More 'no_plan'; > > use Hash::Merge 'merge'; > use Tie::IxHash; > > { > tie my %hash1, 'Tie::IxHash'; > %hash1 = map { ($_ => $_) } (1..10); > is join(" ", keys %hash1), join(" ", sort { $a <=> $b } keys %hash1), 'Keys are sorted'; > > my $merged = merge \%hash1, {}; > local $TODO = "This does not work!"; > is join(" ", keys %$merged), join(" ", sort { $a <=> $b } keys %$merged), 'Keys are still sorted after merge'; > } > > { > tie my %hash1, 'Tie::IxHash'; > %hash1 = map { ($_ => $_) } (1..10); > is join(" ", keys %hash1), join(" ", sort { $a <=> $b } keys %hash1), 'Keys are sorted'; > > my $m = new_merge_into(); > $m->merge(\%hash1, {}); > is join(" ", keys %hash1), join(" ", sort { $a <=> $b } keys %hash1), 'Keys are still sorted'; > } > > { > tie my %hash1, 'Tie::IxHash'; > %hash1 = map { ($_ => $_) } (1..10); > is join(" ", keys %hash1), join(" ", sort { $a <=> $b } keys %hash1), 'Keys are sorted'; > > tie my %hash2, 'Tie::IxHash'; > %hash2 = map { ($_ => $_) } (11..20); > > my $m = new_merge_into(); > $m->merge(\%hash1, \%hash2); > is join(" ", keys %hash1), join(" ", sort { $a <=> $b } keys %hash1), 'Keys are still sorted'; > } > > sub new_merge_into { > my $m = Hash::Merge->new; > $m->specify_behavior > ({ > # basically this is LEFT_PRECEDENT with the case HASH -> > # HASH modified > 'SCALAR' => { > 'SCALAR' => sub { $_[0] }, > 'ARRAY' => sub { $_[0] }, > 'HASH' => sub { $_[0] }, > }, > 'ARRAY' => { > 'SCALAR' => sub { [ @{ $_[0] }, $_[1] ] }, > 'ARRAY' => sub { [ @{ $_[0] }, @{ $_[1] } ] }, > 'HASH' => sub { [ @{ $_[0] }, values %{ $_[1] } ] }, > }, > 'HASH' => { > 'SCALAR' => sub { $_[0] }, > 'ARRAY' => sub { $_[0] }, > 'HASH' => sub { _merge_into_hashes( $_[0], $_[1] ) }, > }, > }); > $m; > } > > sub _merge_into_hashes { > my $self = &Hash::Merge::_get_obj; > > my ( $left, $right ) = ( shift, shift ); > if ( ref $left ne 'HASH' || ref $right ne 'HASH' ) { > die 'Arguments for _merge_hashes must be hash references'; > } > > foreach my $leftkey ( keys %$left ) { > if ( exists $right->{$leftkey} ) { > $self->merge( $left->{$leftkey}, $right->{$leftkey} ); > } > } > > foreach my $rightkey ( keys %$right ) { > if ( !exists $left->{$rightkey} ) { > $left->{$rightkey} = $right->{$rightkey}; > } > } > }