Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Pseudo-hash intrusion...

by dragonchild (Archbishop)
on Jun 21, 2001 at 18:33 UTC ( #90372=perlquestion: print w/ replies, xml ) Need Help??
dragonchild has asked for the wisdom of the Perl Monks concerning the following question:

I've got a listref of hashrefs. All the hashrefs have the same keys. I'm trying to do the following:

my @bar = sort $sortfunc @$foo;

Where $foo is the listref of hashrefs and $sortfunc is defined as sub { $a->{'blah'} cmp $b->{'blah'} }. Now, whenever I try and execute this, I get:

No such pseudo-hash field "blah" at reader.pl line 138.

Line 138 is the definition of $sortfunc.

How do I get the interpreter to not view $foo as a pseudo-hash?

(While I'm on the topic, I personally think pseudo-hashes were a really bad idea, conceptually. But, that's just me.)

Comment on Pseudo-hash intrusion...
Select or Download Code
Re: Pseudo-hash intrusion...
by damian1301 (Curate) on Jun 21, 2001 at 18:48 UTC
    First, @$foo is an arrayref, not a hashref. You can make it seem like a hashref by the @{$foo} thingies.

    Second, just do this.

    my @bar = sort{@{$foo->{$a}} cmp @{$foo->{$b}}} @$foo;

    I might be wrong on this because I am not too familiar in the area, please point it out to me if I am. Thank you.

    UPDATE:jeffa has pointed out to me how I could fix this...
    my @bar = sort{$foo->{$a} cmp $foo->{$b}} @$foo;
    $_.=($=+(6<<1));print(chr(my$a=$_));$^H=$_+$_;$_=$^H; print chr($_-39); # Easy but its ok.
      This is still broken.
      Inside the sort {}, $a will be one of the list inside $foo, and $b another, so that's how you get the
      No such pseudo-hash field "HASH(0x10a57c)" at ./listref line 22.
      error, because you have coerced the $foo->{$a} to a pseudo-hash reference when it is really an array reference. The error occurs because If $foo were really a pseudo-hash, it should have a hash as the first element, (which it does) which contains a field to match $a which $foo doesn't.

      Within the sort command, $a is already dereferenced, so you must use my @bar = sort {$a->{blah} cmp $b->{blah} } @$foo;
      Where the names of the fields being compared are the same ('blah' in this case).

      my $foo = [ {blah=>5,d=>1}, {blah=>4,d=>2}, {blah=>3,d=>3}, {blah=>2,d=>4}, {blah=>1,d=>5}]; my @bar = sort {$a->{blah} cmp $b->{blah} } @$foo; print join(',',map {$_->{blah}} @bar), $/;
      worked for me.

      P.S. If this had been an array of arrays, the message is more clear :

      my $foo = [ [5,1], [4,2], [3,3], [2,4], [1,5]]; my @bar = sort {$foo->{$a} cmp $foo->{$a} } @$foo; # should be my @bar = sort {$a[0] cmp $b[0]} @$foo;
      generates Can't coerce array into hash at ./listref line 33.
      which is a bit more useful.
      --
      Brovnik
Re: Pseudo-hash intrusion...
by runrig (Abbot) on Jun 21, 2001 at 18:59 UTC
    I got this to work fine under 5.6. It will not work under 5.004. My guess is that something is not as you think it is, are you using strict?
    use strict; my $foo = [ {blah=>'aaa'},{blah=>'ddd'},{blah=>'ccc'} ]; my $sortfunc = sub { $a->{blah} cmp $b->{blah} }; my @arr = sort $sortfunc @$foo;
    For 5.004 you'd have to:
    my @arr = do {local *sortfunc = $sortfunc; sort sortfunc @$foo};
(jeffa) Re: Pseudo-hash intrusion...
by jeffa (Chancellor) on Jun 21, 2001 at 19:00 UTC
    This worked for me, i hope it models your prob:
    use strict; use Data::Dumper; my $loh_ref = [ { blah => 'foo'}, { blah => 'bar'}, { blah => 'baz'}, ]; my @bar = sort{ $a->{blah} cmp $b->{blah} } @$loh_ref; print Dumper @bar;
    I wonder why you are using hashes, especially if they have the same key . . . but as for pseudo-hashes, they are only effective if you use the fields module.

    Jeff

    R-R-R--R-R-R--R-R-R--R-R-R--R-R-R--
    L-L--L-L--L-L--L-L--L-L--L-L--L-L--
    
      That's just the thing. I'm not using fields.pm. This code worked until I moved the function that does this sort from the main script to a module using Exporter. At that point, I started getting the pseudo-hash error. I'm not even using inheritance at all (except for inheriting from Exporter, but that shouldn't affect anything ... right?)
Re: Pseudo-hash intrusion... (boo)
by boo_radley (Parson) on Jun 21, 2001 at 19:17 UTC
    From perldiag (I think this is only in 5.6, so perlmonk doesn't have it) :
    No such pseudo-hash field ""%s"" (F) You tried to access an array as a hash, but the field name used is not defined. The hash at index 0 should map all valid field names to array indices for that to work.
    Without seeing how your pseudohash is created I imagine that the structure of the array behind $foo, or its hash members is not what you think, or simply doesn't contain the 'blah' key.

    Additionally, perl is probably interpreting @$foo as a pseudohash is because your sort routine references them as such :

    $a->{'blah'} cmp $b->{'blah'}
    maybe
    $$a->{'blah'} cmp $$b->{'blah'}
    would work, but I'm really just guessing there, since your data structure isn't apparent.
Re: Pseudo-hash intrusion... (boo)
by boo_radley (Parson) on Jun 21, 2001 at 19:18 UTC
    From perldiag (I think this is only in 5.6, so perlmonks doesn't have it) :
    No such pseudo-hash field ""%s"" (F) You tried to access an array as a hash, but the field name used is not defined. The hash at index 0 should map all valid field names to array indices for that to work.
    Without seeing how your pseudohash is created I imagine that the structure of the array behind $foo, or its hash members is not what you think, or simply doesn't contain the 'blah' key.

    Additionally, perl is probably interpreting @$foo as a pseudohash is because your sort routine references them as such :

    $a->{'blah'} cmp $b->{'blah'}
    maybe
    $$a->{'blah'} cmp $$b->{'blah'}
    would work, but I'm really just guessing there, since your data structure isn't apparent.
Re: Pseudo-hash intrusion...
by mattr (Curate) on Jun 21, 2001 at 19:18 UTC
    Under 5.005 this worked. I solved a "Can't use subscript on hash deref" error by changing your sort function (added the percent symbols).
    #!/usr/bin/perl use strict; my %R = ( 'blah' => 5 ); my %S = ( 'blah' => 2 ); my %T = ( 'blah' => 3 ); my @barary = qw(); my @fooary = (\%R, \%S, \%T); sub sortfunc { %$a->{'blah'} cmp %$b->{'blah'}; } @barary = sort sortfunc @fooary; print "$_->{blah} " foreach @barary; print "\n";
Re: Pseudo-hash intrusion...
by dragonchild (Archbishop) on Jun 21, 2001 at 19:24 UTC
    Here's an example I made, stripping it down. I didn't get the pseudo-hash error. However, I didn't get any sorting, either. This is almost exactly how I built the bigger thing, which did give me the pseudo-hash error.

    scorpion:/export/home/kinyonro-> cat abcd #!/usr/local/bin/perl use strict; use efgh qw(do_thing); my $foo = [ { blah => 'd' }, { blah => 'b' }, { blah => 'c' }, ]; my $sortfunc = sub { $a->{blah} cmp $b->{blah} }; my @bar = do_thing($foo, $sortfunc); for my $hash (@bar) { print "$_ => $hash->{$_}\n" for keys %$hash; print "\n"; } scorpion:/export/home/kinyonro-> cat efgh.pm package efgh; use Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw(do_thing); use Data::Dumper; sub do_thing { my ($data, $func) = @_; print Data::Dumper->Dump([$data]); my @bar = sort $func @$data; print Data::Dumper->Dump([@bar]); return @bar; } 1; scorpion:/export/home/kinyonro-> abcd $VAR1 = [ { 'blah' => 'd' }, { 'blah' => 'b' }, { 'blah' => 'c' } ]; $VAR1 = { 'blah' => 'd' }; $VAR2 = { 'blah' => 'b' }; $VAR3 = { 'blah' => 'c' }; blah => d blah => b blah => c

    I am very seriously sooooo confused about this. I've never ever worked with pseudo-hashes, and I don't think I ever will. All I know is that they are listrefs where the 0th element is a hashref and the other elements are listrefs. That isn't the case here. (The original data structure was a listref where the 0th element was a listref and the others were hashrefs, but I shifted off the listref, leaving me with a listref of hashrefs. *whimpers*)

Re: Pseudo-hash intrusion...
by runrig (Abbot) on Jun 21, 2001 at 19:26 UTC
    Exporting is your problem. '$a' and '$b' are package variables to your package, but you (presumably) are sorting in package main. While sorting, '$main::a' and '$main::b' are set, but '$package::a' and '$package::b' are not, which is what the subroutine is using. I'm not sure what the solution is yet, but that's your problem.

    Update: Well, I had things slightly backwards not having seen your example above, but glad I helped. Its still rather an ugly solution though having to put the package name in the sortsub thats in the main package... Wish there were something better :-(

      Thanx to runrig, who pointed out that $a and $b are package-scoped, not global-scoped, I modified the sort function to:

      my $sortfunc = sub { $efgh::a->{blah} cmp $efgh::b->{blah} };

      That not only fixed the simple example (where it wasn't sorting), but it also fixed the original app. I have no idea why it was complaining about pseudo-hashes, but I have a working script+module now. :)

Re: Pseudo-hash intrusion...
by stephen (Priest) on Jun 21, 2001 at 19:46 UTC
    Hmm... something's a little odd here. Pseudo-hashes are arrayrefs with a hash associating fieldname with array index as the first member. If @$foo contained a bunch of arrayrefs which contained hashrefs, the error would make sense to me, since Perl might see the first member of $a and $b and get confused.

    Here, though, you say that @$foo contains hashrefs. Therefore $a and $b should both be hashrefs, and there shouldn't be any confusion on Perl's part. So either A. there's a serious bug in Perl, or B. the data in @$foo is not what you think it should be. If you can isolate the behavior into a small standalone program and post it here, then I'll be more willing to believe it's a bug in Perl. :)

    stephen

      After thinking through the situation, it turns out that this is the exact model for what I was doing in the larger script. Note the re-definition of $sortfunc.

      Now, yes I know that there's a definite package-scoping problem, but I'm posting this to see if this is actually a potential problem with the 5.6.0 interpreter and pseudohashes that might come out in other situations, not just one where the programmer (me) is making a scoping error.

      scorpion:/export/home/kinyonro-> cat abcd #!/usr/local/bin/perl use strict; use 5.6.0; use efgh qw(do_thing); ###################################################################### +######### my $foo = [ [ { blah => 'a' }, {blah => 'b'}, ], [ { blah => 'e' }, {blah => 'f'}, ], [ { blah => 'c' }, {blah => 'd'}, ], ]; my $sortfunc = sub { $a->[0]->{blah} cmp $b->[0]->{blah} }; my @bar = do_thing($foo, $sortfunc); for my $lref (@bar) { for my $hash (@$lref) { print "$_ => $hash->{$_}\n" for keys %$hash; } print "\n"; } ###################################################################### +######### $foo = [ { blah => 'd' }, { blah => 'b' }, { blah => 'c' }, ]; $sortfunc = sub { $a->{blah} cmp $b->{blah} }; @bar = do_thing($foo, $sortfunc); for my $hash (@bar) { print "$_ => $hash->{$_}\n" for keys %$hash; print "\n"; } scorpion:/export/home/kinyonro-> cat efgh.pm use strict; use 5.6.0; package efgh; use Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw(do_thing); use Data::Dumper; sub do_thing { my ($data, $func) = @_; print Data::Dumper->Dump([$data]); my @bar = sort $func @$data; print Data::Dumper->Dump([@bar]); return @bar; } 1; scorpion:/export/home/kinyonro-> abcd $VAR1 = [ [ { 'blah' => 'a' }, { 'blah' => 'b' } ], [ { 'blah' => 'e' }, { 'blah' => 'f' } ], [ { 'blah' => 'c' }, { 'blah' => 'd' } ] ]; $VAR1 = [ { 'blah' => 'a' }, { 'blah' => 'b' } ]; $VAR2 = [ { 'blah' => 'e' }, { 'blah' => 'f' } ]; $VAR3 = [ { 'blah' => 'c' }, { 'blah' => 'd' } ]; blah => a blah => b blah => e blah => f blah => c blah => d $VAR1 = [ { 'blah' => 'd' }, { 'blah' => 'b' }, { 'blah' => 'c' } ]; No such pseudo-hash field "blah" at abcd line 32.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://90372]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (7)
As of 2014-07-29 08:11 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (211 votes), past polls