I am inserting 2-dimensional array references into my heap in Perl.
How should I define the 'elements' attribute when constructing my heap so that I can properly use my comparator function?
my $heap = Heap::Simple->new( order => \&byNumOrStr,
elements => [Array => 0]
);
sub byNumOrStr
{
my ( $a, $b ) = @_;
$b->[0] <=> $a->[0] #0-th element is a number.
||
$a->[1] cmp $b->[1]; #1-st element is a number
}
I keep getting back this error:
Can't use string ("2.55") as an ARRAY ref while "strict refs" in use ... (This means I might actually have to compare my "number string" numerically)
Well, it's likely that either $a
or $b
is being passed in as a string. Try printing out this variables after the assignment.
From what I can see from the documentation, when you pass elements => [ Array => 0 ]
, unless the 0th item in the array is an array then you'll only be comparing the values in the first slot of the array.
[Array => $index]
-
Indicates that the elements are array references, with the key at index $index. So now the element can be not just the key, but also associated data.
This means that if 2.55 is in the array like [ 2.55, ... ] then that's what's being passed in as $a
or $b
.
The elements
entry tells H::S
how you want to derive the key. For a completely generic way, it says that you can pass [Function => $code_ref_for_key]
. You could make it like this:
sub first_two_slots {
my $array_ref = shift;
return [ @$array_ref[0,1] ];
}
And then with the order as specified, it would pass that array into your order and specify
my $heap = Heap::Simple->new( order => \&byNumOrStr,
elements => [Function => \&first_two_slots]
);
Original comment left in place: (It's not relevant to how Heap::Simple
calls order).
if byNumOrStr
is called from sort
DON'T assign $a
and $b
in it. Those values are set by sort
. If there is something coming in @_
it's probably not what you want.
Sorting a two-dimensional array doesn't really make sense -- when you sort something, there is a defined order. Having two sort criteria doesn't make it a two-dimensional list... do you mean that you have data that are a list of two elements? e.g.:
my $element = [ '0', 'string' ];
I think Example 1 in the documentation ("where key and value are kept separate") applies here -- you want to sort the references, not the values themselves. So try declaring with elements => "Any"
, and then adjust your sort method to match:
(I was wrong.. it looks like elements => [Array => 0]
is correct, since these are just plain old arrayrefs being sorted.
my $heap = Heap::Simple->new( order => \&byNumOrStr,
elements => [Array => 0],
);
sub byNumOrStr
{
my ( $val1, $val2 ) = @_;
my $result =
$val1->[0] <=> $val2->[0] # the 0th element is a number
||
$val1->[1] cmp $val2->[1]; # the 1st element is a string
# The docs say "this should return a true value if $key1 is smaller than $key2 and a false value otherwise."
return $result == -1;
}
PS. As discussed in Secondary Order in Heap::Simple, the comparison function in Heap::Simple does not want a return value of -1, 0, or 1, but rather true or false. You need to convert the comparison result before returning from the function.