(jeffa) Re: Pseudo-hash intrusion...
by jeffa (Bishop) 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--
| [reply] [d/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?)
| [reply] |
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 :-( | [reply] |
|
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. :)
| [reply] [d/l] |
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.
| [reply] [d/l] [select] |
|
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 | [reply] [d/l] [select] |
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.
| [reply] [d/l] [select] |
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";
| [reply] [d/l] |
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*) | [reply] [d/l] |
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
| [reply] |
|
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.
| [reply] [d/l] |
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};
| [reply] [d/l] [select] |
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.
| [reply] [d/l] [select] |