Hi PerlMonks people!
I have a rather tricky sort question that I've been trying to solve. In my array of hashes I've ID, Distance and RouteDistance. I want to sort on RouteDistance but this value is sometimes 0 and here comes the tricky part. When RouteDistance is 0 I want the sorting to be done on the Distance for this hash instead.In the next example I want to get around the RouteDistance cases where RouteDistance is equal to 0.my @unsortedArray; foreach my $received_xml_post (@ {$xml_post_array{'data'}}) { push @unsortedArray, { 'ID' => $received_xml_post->{'ID'}, 'Distance => $received_xml_post->{'Dis +tance'}, 'RouteDistance' => $received_xml_post- +>{'RouteDistance'}}; } my @sortedArray = sort { $a->{RouteDistance} <=> $b->{RouteDistance || + $a->{Distance} <=> $b->{Distance} } @unsortedArray;
my @unsortedArray; foreach my $received_xml_post (@ {$xml_post_array{'data'}}) { push @unsortedArray, { 'ID' => $received_xml_post->{'ID'}, 'Distance => $received_xml_post->{'Distance'} +, 'RouteDistance' => $received_xml_post->{'Rout +eDistance'}}; } my @sortedArray = sort { if( $a->{RouteDistance} == 0) {return -1} els +e {$a->{RouteDistance} <=> $b->{RouteDistance} $a->{Distance} <=> $b- +>{Distance} } @unsortedArray;
The 2nd code example will just sort everything on Distance. I've done an ugly version of this sorting that first sorts on Distance. Then I loop trough this and save current RouteDistance and in cases where RouteDinstance is equal to 0 I just pick up that previous RouteDistance and add 0.001 to it. However, this solution does not work with exreame cases and therefore I want to find out if there is a better way to handle this type of sorting. I'm sorry in advance for my English (not my native language). This is my first post here by the way so I might have done something wrong with this post but just let me know and I will now to next time.
Update 1: One of the suggestions that was close to achiveing this was this peace of code:
sort { $a->{routedistance} && $b->{routedistance} ? $a->{routedistance} <=> $b->{routedistance} : $a->{distance} <=> $b->{distance} } @ar;
unfortunately, this turned out to not work as I wanted when the RouteDistance was pre-ordered where one of the RouteDistance was zero.
I can add one thing to the table. The value of RouteDistance is not important, as long as it is sorted as I've described above. What I mean by this is that cases where RouteDistance is zero, this value can be replaces to something else, for example previous RouteDistance or nearest + 0.01 / -0.01. The value of RouteDistance will not be used to anything else then just sorting which makes this one option.
Update 2: The problem is not yet solved and and have no good solution for it.. :/
Update 3: The problem is solved. It might be some extreme cases where this all falls apart but with the tests I've done it works.
The solution:
#!/usr/bin/perl use warnings; use strict; my @unsorted_array = ( { ID => 3, Distance => 2.3, RouteDistance => + 4.3 }, { ID => 2, Distance => 1.5, RouteDistance => 2 +.8 }, { ID => 5, Distance => 2.1, RouteDistance => 0 + }, { ID => 1, Distance => 1.7, RouteDistance => 2 +.5 }); my @sorted = sort { if($a->{RouteDistance} == 0 || $b->{RouteDistance} == 0) { return ($a->{Distance} < $b->{Distance}) ? -1 : 1; } elsif ($a->{RouteDistance} == $b->{RouteDistance}) { return 0; } else { return ($a->{RouteDistance} < $b->{RouteDistance}) ? -1 : 1; } } @unsorted_array; foreach my $sorted_row (@sorted) { print "ID: ".$sorted_row->{'ID'}." Distance: ".$sorted_row->{'Dist +ance'}." RouteDistance: ".$sorted_row->{'RouteDistance'}."\n"; }
In reply to Sorting an array of hashes with an exception by martin_87
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |