Home > Archive > PERL Beginners > April 2006 > sort {} to work with undef values when its expecting an object
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
sort {} to work with undef values when its expecting an object
|
|
| JupiterHost.Net 2006-04-25, 7:00 pm |
| Hello List,
I have a sort() issue that is a bit odd and any input wouls be most
appreciated :)
The code:
use strict;
use warnings;
....
for my $obj(
sort {
$a->value() cmp $b->value()
||
$a->part('Name')->value() cmp $b->part('Name')->value()
}
grep { defined } @objects
) {
....
$a/$b->value() always works since if $a/$b is defined its an object with
a method called value()
$a/$b->part('Name') returns an object that also has a method called
value() or undefined if there is no "Name" part
The sort works perfect for what I need, *except* when
$a/$b->part('Name') does not return an object itself. Then it dies with
"Can't call method value() on undefined value."
So how can I keep my sort() but avoid/work with the "can't call method
on undefined value" error when $a/$b->part('Name') returns undef instead
of an object?
I've put them in valriables depending on defined()ness and done
$name_a cmp $name_b
Which is error free but also doesn't appear to sort it properly :(
TIA!
| |
| Timothy Johnson 2006-04-25, 7:00 pm |
|
Just a thought, but couldn't you put the logic in your grep statement?
Something like this:
grep {defined($_->value()) or defined($_->part('Name')->value())}
@objects;
-----Original Message-----
From: JupiterHost.Net [mailto:mlists@jupiterhost.net]=20
Sent: Tuesday, April 25, 2006 12:22 PM
To: beginners@perl.org
Subject: sort {} to work with undef values when its expecting an object
<snip>
The code:
use strict;
use warnings;
....
for my $obj(
sort {
$a->value() cmp $b->value()
||
$a->part('Name')->value() cmp $b->part('Name')->value()
}
grep { defined } @objects
) {
....
$a/$b->value() always works since if $a/$b is defined its an object with
a method called value()
<snip>
The sort works perfect for what I need, *except* when=20
$a/$b->part('Name') does not return an object itself. Then it dies with=20
"Can't call method value() on undefined value."
<snip>
| |
| Paul Lalli 2006-04-25, 7:00 pm |
| JupiterHost.Net wrote:
> I have a sort() issue that is a bit odd and any input wouls be most
> appreciated :)
>
> for my $obj(
> sort {
> $a->value() cmp $b->value()
> ||
> $a->part('Name')->value() cmp $b->part('Name')->value()
> }
> grep { defined } @objects
> ) {
>
> ...
> $a/$b->part('Name') returns an object that also has a method called
> value() or undefined if there is no "Name" part
>
> The sort works perfect for what I need, *except* when
> $a/$b->part('Name') does not return an object itself. Then it dies with
> "Can't call method value() on undefined value."
>
> So how can I keep my sort() but avoid/work with the "can't call method
> on undefined value" error when $a/$b->part('Name') returns undef instead
> of an object?
Not enough information. What do you want the sort to return if
$a->part('Name') is undefined but $b->part('Name') is an object? What
if both are undefined?
The obvious answer is that you need to figure out what your sort should
do in each case, and program for it accordingly. If an object with no
Name should come before one with a name, for example:
$a->value() cmp $b->value()
||
(
defined $a->part('Name') ?
(defined $b->part('Name') ?
$a->part('Name')->value() cmp $b->part('Name')->value() )
: 1)
: (defined $b->part('Name') ? -1 : 0)
)
Untested, but the way this reads to me is:
sort by the value() of $a and $b
if the values are equal, then:
if $a has 'Name'
if $b has 'Name'
sort by the Name->value() of $a and $b
else ($b does not have Name, $a does)
put $b first
endif
else ($a does not have a name, $b does)
if $b has a 'Name'
put $a first
else (neither $a nor $b have a name)
doesn't matter which comes first
endif
endif
endif
Hope this helps,
Paul Lalli
| |
| JupiterHost.Net 2006-04-25, 7:00 pm |
|
Timothy Johnson wrote:
> Just a thought, but couldn't you put the logic in your grep statement?
>
> Something like this:
>
> grep {defined($_->value()) or defined($_->part('Name')->value())}
> @objects;
The only problem is then that the object woudl be completely skipped.
I need all objects regardless of if their part call returns and object
or undef :(
Perhaps their is a logic I can do something like that, like 2 sort()s or
a map() or ??
Thanks for the input!
> -----Original Message-----
> From: JupiterHost.Net [mailto:mlists@jupiterhost.net]
> Sent: Tuesday, April 25, 2006 12:22 PM
> To: beginners@perl.org
> Subject: sort {} to work with undef values when its expecting an object
>
> <snip>
>
> The code:
>
> use strict;
> use warnings;
> ...
> for my $obj(
> sort {
> $a->value() cmp $b->value()
> ||
> $a->part('Name')->value() cmp $b->part('Name')->value()
> }
> grep { defined } @objects
> ) {
> ...
>
> $a/$b->value() always works since if $a/$b is defined its an object with
>
> a method called value()
>
> <snip>
>
> The sort works perfect for what I need, *except* when
> $a/$b->part('Name') does not return an object itself. Then it dies with
> "Can't call method value() on undefined value."
>
> <snip>
>
>
>
| |
| JupiterHost.Net 2006-04-25, 7:00 pm |
|
Jay Savage wrote:
> On 4/25/06, JupiterHost.Net <mlists@jupiterhost.net> wrote:
>
>
>
> How does it not sort properly? We need some sample data for that.
>
When using:
$a->part('Name')->value() cmp $b->part('Name')->value-()
in the sort funtion and all $a ans $b's part's have Names then it sorts
properly.
If I change it to
$name_a cmp $name_b
where $name_a and $name_n are set by a ternary check for definedness
and set to the method call's value or some default value if itd
undefined) it does not error out but not sort on $a or $b :)
> Generally, though, you have two options. One is to trap the error with
> eval or some other method. The other is to insert some logic to check
I'll havew to try that, eval since the logci just isn;t working :)
> that the methods are defined before you call them...and decide how you
> want to handle object that have no value. Perl is basically saying "I
> can't sort it by value if it doesn't have a value". Either check for
> definedness in the sort, or verify the data before you sort it and set
> the bad data aside to deal with later.
>
> This is one of the quirks of dealing with methods. If a method isn't
> defined, it's more like an undefined subroutine call than an undefined
> variable, in that attempting to call a method on an object for which
> it's not defined is fatal.
>
> HTH,
>
> --jay
> --------------------------------------------------
> This email and attachment(s): [ ] blogable; [ x ] ask first; [ ]
> private and confidential
>
> daggerquill [at] gmail [dot] com
> http://www.tuaw.com http://www.dpguru.com http://www.engatiki.org
>
> values of â will give rise to dom!
| |
| Tom Phoenix 2006-04-25, 7:00 pm |
| On 4/25/06, JupiterHost.Net <mlists@jupiterhost.net> wrote:
> sort {
> $a->value() cmp $b->value()
> ||
> $a->part('Name')->value() cmp $b->part('Name')->value()
> }
> grep { defined } @objects
But sometimes $a->part('Name') returns undef, so the sort fails.
> I need all objects regardless of if their part call returns and object
> or undef :(
>
> Perhaps their is a logic I can do something like that, like 2 sort()s or
> a map() or ??
It almost sounds like you're talking about a Schwartzian Transform. In
fact, you could process your data in steps, as the Schwartzian
Transform does. (Warning: Untested code follows.)
First, you pick out the items you want:
my @desired_data =3D grep { defined } @objects;
Next, transform each data item into an array reference holding the
original item and anything useful-to-know that you don't want to have
to recompute inside the sort block. In this case, that's your method
calls. I'm thinking something like this?
my @transformed_data =3D map {
my $part_name =3D $_->part('Name');
my $part_name_value =3D (defined $part_name)
? $part_name->value()
: ""; # empty string
[ $_, $_->value(), $part_name_value ]
} @desired_data;
Now you can sort efficiently on the derived data:
my @sorted_data =3D sort {
$a->[1] cmp $b->[1] # value
or
$a->[2] cmp $b->[2] # part_name_value
} @transformed_data;
Finally, strip away the stuff you don't need anymore:
my @result =3D map $_->[0], @sorted_data;
And you've got your data in order. Is that anything like the order you want=
ed?
In the tradition of the S.T., you should string the steps together
without the intermediate arrays. But if you've followed along up to
here, you can do that on your own.
Hope this helps!
--Tom Phoenix
Stonehenge Perl Training
| |
| JupiterHost.Net 2006-04-26, 6:58 pm |
|
Tom Phoenix wrote:
> On 4/25/06, JupiterHost.Net <mlists@jupiterhost.net> wrote:
>
>
>
>
> But sometimes $a->part('Name') returns undef, so the sort fails.
>
>
>
>
> It almost sounds like you're talking about a Schwartzian Transform. In
> fact, you could process your data in steps, as the Schwartzian
> Transform does. (Warning: Untested code follows.)
>
> First, you pick out the items you want:
>
> my @desired_data = grep { defined } @objects;
>
> Next, transform each data item into an array reference holding the
> original item and anything useful-to-know that you don't want to have
That was my first plan of attack and in fact had it all in a hash to
sort on its keys, but I discovered that the module in question does some
nice override of the object and it gets stringified in scalar context:
print $obj->value(); # prints "foo"
%lookup_table = (
obj => $obj,
....
$lookup_table{'obj'} is now the string "foo" not the object, and I've
found no way to reference it in the hash since its value is not
necessarily unique.
I'm sure I can get a good idea from your input that will help with this,
thanks!
|
|
|
|
|