saiprathapreddy has asked for the wisdom of the Perl Monks concerning the following question:

Actual : @Foods=qw(abc abc1 abc2 abc_1 abc_2 abc01_1);

After sorting it's printing like this
: abc abc01_1 abc1 abc2 abc_1 abc_2

But it should be like this
: abc abc_1 abc_2 abc01_1 abc1 abc2

Replies are listed 'Best First'.
Re: sorting an array if sting having _
by choroba (Cardinal) on Dec 12, 2013 at 11:05 UTC
    Please, explain why abc01_1 goes after abc_1, but before abc1. See sort for details on how to sort.
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      _ (underscore has taken high priority comapred to other values that is why)

        So really you want to split your strings on the underscore and then sort by the first part, and if they are equal, by the second part? The Schwartzian Transform helps you to do this:

        my @sortedFoods = map { $_->[0] } sort { $a->[1] cmp $b->[1] or ($a->[2]//'') cmp ($b->[2]//'') } map { [ $_, split /_/ ] } @Foods;

        Note that this sorts the pieces like strings and ignores the fact that some parts of them are numbers. So abc10 comes before abc2.

        Update: added parentheses to take into account precedence of //. Thanks choroba!

      A reply falls below the community's threshold of quality. You may see it by logging in.
Re: sorting an array if sting having _
by wind (Priest) on Dec 12, 2013 at 18:10 UTC
    The underscore (_) comes after the decimals and capital letters using perl's cmp operator but before the lower case letters. If you'd like it to be before numbers, then simply create a custom sort by moving it before:
    use strict; use warnings; my @foods = qw(abc abc1 abc2 abc_1 abc_2 abc01_1); # Create a Custom Sort my @sort_char_order = sort map {chr $_} (1..127); # Move '_' to before '0' in your list; my @your_char_order = map {$_ eq '0' ? ('_', '0') : $_ eq '_' ? () : $ +_} @sort_char_order; my $sort_char_order = join '', @sort_char_order; my $your_char_order = join '', @your_char_order; my $trans_word = eval qq{ sub { my \$param = shift; \$param =~ tr/\Q$your_char_order\E/\Q$sort_char_order\E/; return \$param; } }; # Sort by your custom definition my @sorted_foods = map { $_->[0] } sort { $a->[1] cmp $b->[1] } map { [ $_, $trans_word->($_) ] } @foods; print join ' ', @sorted_foods; # abc abc_1 abc_2 abc01_1 abc1 abc2
    - Miller