Re: Numeric Sorting on Characters
by choroba (Cardinal) on Aug 14, 2013 at 19:18 UTC
|
| [reply] [d/l] [select] |
|
|
Hi choroba,
Can you explain what is happening when @sorted is generated? I'm not sure how you were able to grep after sort. I do understand that the grep checks if the value equals "-", otherwise is pushes it to @dashed, but why "and 0"? Thanks!
| [reply] |
|
|
When functions are chained, they are called from right to left. So, that's what happens: Keys are taken. For each key, if it is not a dash, it is left in the list that is later sorted. If it is a dash, it is pushed to @dashed and 0 is returned so grep removes it from the list to be sorted.
| [reply] |
Re: Numeric Sorting on Characters
by McA (Priest) on Aug 14, 2013 at 19:19 UTC
|
sort {
($passes->{$a}->{'cpu'} ne '-' ? $passes->{$a}->{'cpu'} : 0)
<=>
($passes->{$b}->{'cpu'} ne '-' ? $passes->{$b}->{'cpu'} : 0)
} keys %{$passes}
UPDATE: In addition to choroba's solution you're able to assign a different value in case of '-'.
McA | [reply] [d/l] |
|
|
>perl -wMstrict -le
"my @unsorted = (1, 10, '-', 2, -3, 20, '-', '-', 3, 0, 2, 11, 8, 7);
;;
my @sorted = sort numeric_ascending_with_dash_leftmost @unsorted;
print qq{@sorted};
;;
@sorted = sort { -numeric_ascending_with_dash_leftmost() } @unsorted;
print qq{reversed: @sorted};
;;
print qq{still unsorted: @unsorted};
;;
sub numeric_ascending_with_dash_leftmost {
return $a eq '-' ? -1 :
$b eq '-' ? 1 :
$a <=> $b
;
}
"
- - - -3 0 1 2 2 3 7 8 10 11 20
reversed: 20 11 10 8 7 3 2 2 1 0 -3 - - -
still unsorted: 1 10 - 2 -3 20 - - 3 0 2 11 8 7
| [reply] [d/l] [select] |
Re: Numeric Sorting on Characters
by Laurent_R (Canon) on Aug 14, 2013 at 20:57 UTC
|
The problem is that this warning tells you something about your data not being what you expected. It could be important or absolutely a non-issue, you did not tell us anything about the functional context.
Ignoring it altogether is not a very good idea IMHO, because the data resulting from the sort will probably still be plagued with these unexpected values.
Filtering out the non-standard values with a grep before the sort is already better, if that fits your goals, i.e. if removing these values does not harm the rest of your process. Another possibility is to decide that these non standard values must always come before (or after) any other values, which means changing your sorting procedure or having a preliminary step before the sort. Another preprocessing strategy might be to replace temporarily the '-' by a very large or very small positive or negative value, or a null value, whatever might set these values asides without having the warnings.
But you alone can decide what to do so long as we don't have any idea of what your are sorting.
| [reply] |
Re: Numeric Sorting on Characters
by Kenosis (Priest) on Aug 14, 2013 at 21:16 UTC
|
If you're using Perl v5.14+, you could use the r (for return the modified string) modifier in a substitution:
use strict;
use warnings;
my %hash = map { $_ => 1 } qw/987-665-888 456-123-000 000-000-000 123-
+456-789/;
print "$_\n" for sort { $a =~ s/-//gr <=> $b =~ s/-//gr } keys %hash;
Output:
000-000-000
123-456-789
456-123-000
987-665-888
Hope this helps! | [reply] [d/l] [select] |
|
|
halecommarachel supplies no example data, so this point is a bit unclear, but I assume that the real data has elements that are a '-' (dash) rather than that contain dashes. E.g.,
qw(1 10 - 2 -3 20 - - 3 0 2 11 8 7);
rather than
qw/987-665-888 456-123-000 000-000-000 123-456-789/
Caveat Programmor.
| [reply] [d/l] [select] |
|
|
/me nods ...
In which case, if careful research into the problem confirms that,: - Yes, that dash is legitimate data, and
- there is no bug either in this program or in the upstream source, and
- the downstream program(s) will know what to do, and therefore,
- here is how we wish to sort it,
... (heh) ...
Then, as you know, the Perl sort verb relies upon a subroutine to do the sort-comparison, “and this is why.” Although it is most frequently a “one-liner,” it can be a much more elaborate thing which receives two parameters, $a and $b. (And, if you do several sorts the same way, it can be a separate, not-inline, subroutine that all of them use.) All of which is well and good ... but I think that I’m in the majority thinking that a bug .. somewhere upstream .. has been uncovered here.
| |
Re: Numeric Sorting on Characters
by locked_user sundialsvc4 (Abbot) on Aug 14, 2013 at 20:54 UTC
|
Hmmm... the presence of a single “-” seems quite suspicious to me ... have you looked at the corresponding record in the input data, and if so, is it really just a dash? Does this look like a possible bug in the program that produced the file? (Hey, it happens ... a lot.)
“Making the immediate bug go-away” sometimes leaves you in a situation that is much worse. Why is that dash there? Is it really there (or is your parsing algorithm insufficient?). Is it really correct to code your program to detect and to accept it? Maybe the proper answer to all 3 questions is yes. But then again, the software might be trying to tell you something.
| |
|
|
| [reply] |
|
|
| [reply] |
Re: Numeric Sorting on Characters
by johngg (Canon) on Aug 14, 2013 at 21:31 UTC
|
Another way is to use a Schwartzian Transform passing the key, an indicator whether the cpu is "-" (1 - TRUE or 0 - FALSE) and the cpu value in an array ref. Sorting can then be done on the indicator first then on cpu value but the second sort term is a ternary so that comparing two items with a "-" cpu value immediately returns zero.
$ perl -Mstrict -Mwarnings -E '
my $passes = {
t1 => { cpu => 73, xx => 3 },
t2 => { cpu => q{-}, xx => 7 },
t3 => { cpu => 17, xx => 0 },
t4 => { cpu => 49, xx => 6 },
t5 => { cpu => q{-}, xx => 4 },
t6 => { cpu => 11, xx => 5 },
};
say for
map { $_->[ 0 ] }
sort {
$a->[ 1 ] <=> $b->[ 1 ]
||
( $a->[ 1 ] ? 0 : $a->[ 2 ] <=> $b->[ 2 ] )
}
map { [
$_,
$passes->{ $_ }->{ cpu } eq q{-},
$passes->{ $_ }->{ cpu },
]
}
keys %$passes;'
t6
t3
t4
t1
t2
t5
$
I hope this is of interest.
Update: Ignore this, it doesn't seem to be sorting correctly :-(
Update 2: I was bitten on the bum by a silly precedence problem that should have occurred to me sooner. Replacing
sort {
$a->[ 1 ] <=> $b->[ 1 ]
||
$a->[ 1 ] ? 0 : $a->[ 2 ] <=> $b->[ 2 ]
}
with
sort {
$a->[ 1 ] <=> $b->[ 1 ]
||
( $a->[ 1 ] ? 0 : $a->[ 2 ] <=> $b->[ 2 ] )
}
solved the problem.
| [reply] [d/l] [select] |