http://qs321.pair.com?node_id=1232325

dideod.yang has asked for the wisdom of the Perl Monks concerning the following question:

Hi monks. I want to sort below example. I want to print sorting by number but before that, I have to print sorting by alphabet first. Can you help me?
use strict; use warnings; my @aa = qw/ CORE1 CORE12 CORE8 CORE233 COREA11 COREA12 COREA130 COREA115 /; # It sort only alphabet. I have to sort alphabet also number. @aa = sort @aa; print "@aa\n"; # I want to print CORE1 CORE12 CORE233 CORE8 COREA11 COREA12 COREA115 +COREA130

Replies are listed 'Best First'.
Re: sorting number
by GrandFather (Saint) on Apr 09, 2019 at 06:44 UTC

    A fairly standard approach is to break the identifier up into a letter part and a number part, sort by each as needed, then join the bits back together again. There is a Perl idiom that makes that fairly easy and clean to do:

    use strict; use warnings; my @rawList = qw( CORE1 COREA11 CORE12 COREA130 CORE8 CORE233 COREA12 COREA115 ); my @sortedList = # Join letter and number parts back together map{$_->[0] . $_->[1]} # sort first by letter part, then if that is equal sort by number +part sort {$a->[0] cmp $b->[0] || $a->[1] <=> $b->[1]} # Use a regex to split each item into a letter part and a number p +art map{[/([^\d]+)([\d]+)/]} @rawList; print join "\n", @sortedList;

    Prints:

    CORE1 CORE8 CORE12 CORE233 COREA11 COREA12 COREA115 COREA130

    Note that map takes a list, processes each element, and returns a new list. The expression executes its main parts essentially from right to left: the last map executes first, then the sort, then finally the first map.

    Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
Re: sorting number
by NetWallah (Canon) on Apr 09, 2019 at 04:38 UTC
    Read the sort function documentation.

    The relevant parts are:
    * <=> does NUMERIC comparison.
    * cmp does text/string comparison

    You also need to extract the numeric part from the string when you want a numeric sort.
    Regular expressions are useful for that.

                    "It's ten o'clock... Do you know where your AI programs are?"

      Thanks replay, yes I know each function. but I want to use both of them. Is it possible to use both of them?
Re: sorting number
by haukex (Archbishop) on Apr 09, 2019 at 07:47 UTC
Re: sorting number
by Tux (Canon) on Apr 09, 2019 at 06:22 UTC
    my @sorted = map { $_->[0] } sort { $a->[1] cmp $b->[1] } map { [ $_, s/^CORE//r =~ s/(\d+)/sprintf "%06d", $1/ger ] } @aa;

    Enjoy, Have FUN! H.Merijn
      [ $_, s/^CAORE//r =~ s/(\d+)/sprintf "%06d", $1/ger ] } @aa;

      I don't understand the  s/^CAORE//r part of this expression. It seems to be doing nothing, and the sorted output is the same without it:

      c:\@Work\Perl\monks>perl -wMstrict -le "my @aa = qw( CORE1 CORE12 CORE8 CORE233 COREA11 COREA12 COREA130 COREA115 ); my @sorted = map { $_->[0] } sort { $a->[1] cmp $b->[1] } map { [ $_, s/(\d+)/sprintf \"%06d\", $1/ger ] } @aa; print qq{@sorted}; " CORE1 CORE8 CORE12 CORE233 COREA11 COREA12 COREA115 COREA130
      Can you please elaborate?


      Give a man a fish:  <%-{-{-{-<

        1. It is a typo (CAORE instead of CORE) - answer edited
        2. Not required indeed

      Enjoy, Have FUN! H.Merijn
Re: sorting number
by AnomalousMonk (Archbishop) on Apr 09, 2019 at 07:01 UTC
    # I want to print CORE1 CORE12 CORE233 CORE8 COREA11 COREA12 COREA115 COREA130

    This is not the ordering produced by either Tux's solution or by GrandFather's solution (both of which produce the same ordering), and I don't understand what you want | the internal logic of the ordering you have specified. Can you please clarify?


    Give a man a fish:  <%-{-{-{-<

Re: sorting number
by johngg (Canon) on Apr 09, 2019 at 10:03 UTC

    Yes, the problem description and desired output do not seem to match. Anyway, here's a GRT for sorting letters then numbers, casting non-compliant lines to the top of the output.

    use 5.026; use warnings; my @aa = qw{ CORE1 CORE12 CORE8 duffdata CORE233 COREA11 COREA12 COREA130 COREA12b COREA115 }; say for map { substr $_, 54 } sort map { my( $letters, $digits ) = m{^([A-Za-z]+)(\d+)$} ? ( $1, $2 ) : ( q{}, 0 ); pack q{A50NA*}, $letters, $digits, $_; } @aa;

    The output.

    COREA12b duffdata CORE1 CORE8 CORE12 CORE233 COREA11 COREA12 COREA115 COREA130

    I hope this is of interest.

    Cheers,

    JohnGG

Re: sorting number
by kcott (Archbishop) on Apr 09, 2019 at 07:47 UTC

    G'day dideod.yang,

    What you have as "I want to print ..." is not really sorted. Perhaps you wrote COREA12 and COREA115 around the wrong way. If that's the case, you'd need to split each element into alphabetic and numeric parts but do a string comparison on both of them:

    $ perl -E ' say map "$_->[0]$_->[1] ", sort { $a->[0] cmp $b->[0] || $a->[1] cmp $b->[1] } map [/(\D+)(\d+)/], qw{ CORE1 CORE12 CORE8 CORE233 COREA11 COREA12 COREA130 COREA115 } ' CORE1 CORE12 CORE233 CORE8 COREA11 COREA115 COREA12 COREA130

    — Ken

      My guess is that it was the CORE8 that was misplaced, and GrandFather's and Tux's solutions are the expected output.

      I suppose you meant to write <=> on the right side? Otherwise your code gives the same output as a plain sort

        "My guess is that it was the CORE8 that was misplaced, ..."

        Quite possibly - it's all guesswork. :-)

        "I suppose you meant to write <=> on the right side?"

        No, cmp was intended. I was aiming to indicate that cmp would give "11 115 12 130"; whereas <=> would give "11 12 115 130".

        It would appear I failed to communicate my intent. Thanks for pointing this out and giving me the opportunity to provide clarification.

        — Ken

      Perhaps you wrote COREA12 and COREA115 around the wrong way.

      But then the desired sort order just becomes the default lexi sort:

      c:\@Work\Perl\monks>perl -wMstrict -le "my @sorted = sort qw(CORE1 CORE12 CORE8 CORE233 COREA11 COREA12 COREA130 COREA115) ; print qq{@sorted}; " CORE1 CORE12 CORE233 CORE8 COREA11 COREA115 COREA12 COREA130


      Give a man a fish:  <%-{-{-{-<

        See my response to ++Eily's post - he asked about the same thing.

        — Ken

Re: sorting number
by kcott (Archbishop) on Apr 10, 2019 at 07:51 UTC

    I've front-paged this. This is not reflection of the OP which, as many have pointed out, leaves a lot to be desired. It is a reflection of the excellent responses: when checking Best Nodes of the Day after work today, 7 of the top 10 were from this thread.

    — Ken

Re: sorting number
by Marshall (Canon) on Apr 10, 2019 at 03:23 UTC
    It would help the Monks greatly if the spec was more clear.
    # I want to print CORE1 CORE12 CORE233 CORE8 COREA11 COREA12 COREA115
    An alpha sort order will get 1,12,233,8 for CORE
    A numeric sort order will get 11,12,115 for COREA
    But a single general sort routine cannot do both.
    At a minimum you have to specify more rules about how to reach your desired output.

    There are many ways to code sorts in Perl. Some of them are quite clever and faster for large sorts versus a more straightforward approach. I personally start thinking about these fancy things when the array is >1,000 or in situations where the code is going to be run very often, by that I mean more than once per second.