http://www.perlmonks.org?node_id=1080605


in reply to Re: Custom Sort An AoA
in thread Custom Sort An AoA

kennethk,
This will work and that's what matters. Can you think of a more general purpose solution though (consider if the elements had been numerical and what was desired was numerical order for instance).

Cheers - L~R

Replies are listed 'Best First'.
Re^3: Custom Sort An AoA
by SuicideJunkie (Vicar) on Apr 01, 2014 at 17:43 UTC

    If all the data were numeric and limited in length, you could zero-pad it before the join and then CMP it since <=> will probably explode on longer arrays.

    If you need it to be fully generic, you could always break down and make the sort block be a complex sub that loops over the elements and returns once it finds a difference.

    sub sortIt { my $result = @$a <=> @$b; my $idx = $#$a; while (!$result && $idx >=0) { $result = $a->[$idx] cmp $b->[$idx]; $idx--; } return $result; }
      I'd do it too with an extra helper function, but I would keep the first condition out (for readability, flexibility and reuse)

      something like

      sub cmp_vec { # return either -1,0 or 1 comparing over two equally sized arrays } sort { @$a <=> @$b or cmp_vec($a,$b) } @list;

      for full flexibility a cmp-function could be passed as call-back in third position.

      As a side note, I'm not sure if this could be done with Perl6 Meta ops, something like @a >>cmp<< @b (after reversing of course).

      Cheers Rolf

      ( addicted to the Perl Programming Language)

      update

      something like

      sub cmp_vec { my ($a,$b) = @_; for (reverse 0.. @$a-1) { if (my $x= $a->[$_] cmp $b->[$_]) { return $x } } return 0; ]
        LanX,
        You may be amused to know that this question is being used to help me identify and organize execution paths through 6502 Assembly. (See also my response to shmem).

        Cheers - L~R

      SuicideJunkie,
      ...and limited in length....

      You would also need to know that limit and pad everything at every level or else it would still be very complex.

      If you need it to be fully generic...

      Ah yes, this is along the lines of what I was looking for.

      Cheers - L~R

        Ah yes, this is along the lines of what I was looking for.

        Although it feels a bit strange spoon-feeding you a solution... ;)

        Implementing the orcish maneuver as kennethk suggested is left as an excercise for the reader.

        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re^3: Custom Sort An AoA
by kennethk (Abbot) on Apr 02, 2014 at 18:09 UTC
    Lots of discussion has ensued since I checked out yesterday, but the most generic treatment I can think of is essentially pre-computing the comparison strings in two passes, so that you can be sure that your arguments are properly conditioned:
    #!/usr/bin/perl use strict; use warnings; my @input = ( ['blah', 'asdf', 'foo', 'bar'], ['two'], ['zzz', 'def', 'ghi'], ['one'], ['mmm', 'def', 'ghi'], ['qqq', 'xyz', 'aaa'], ); my @list = do { my $max_array = 0; my $max_word = 0; for (@input) { $max_array = @$_ if @$_ > $max_array; for (@$_) { $max_word = length if length > $max_word; } } my $digit = 1 + int log($max_array)/log(10); my $format = "%$digit.d" . ("%-${max_word}s") x $max_array; my %cache = map {$_ => sprintf $format, 0+@$_, reverse(@$_), ( +'') x $max_array} @input; sort {$cache{$a} cmp $cache{$b}} @input; }; $" = "', '"; print "['@$_']\n" for @list;
    My measurement approach means that it's no longer sensitive to delimiter choice, but of course this is a conservative approach to that since it assumes one $max_word for all terms. The empty string padding in the sprintf is just to silence warnings.

    If you want a numerical sorting for elements in place of lexical sorting, you could swap "%-${max_word}s" in the format constructor to "%${max_word}.d" More complex the pattern, the more complex the construction - you can see how impressively the code exploded for just these changes. You could even support a mixed mode by flopping between "%-${max_word}s" and "%${max_word}.d" depending on looks_like_number EXPR.


    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.