Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things

comment on

( #3333=superdoc: print w/replies, xml ) Need Help??
Ever wanted to sort on a computed value or a certain column in a string within an array. It can get pretty tricky to do right. You only want to compute the value you're sorting on once for each array element not every time you do a comparison throughout the sort.

One key function you'll want to know how to use is map. Map allows you to apply a change to a list and get back a new list with the changes.

There are two ways you can use the map function;
#map BLOCK, LIST #or something like @revwords=map{ @letters=split(//); @revletters=reverse(@letters); join(' ',@revletters); } @words; #or #map EXPR, LIST @asciival=map(ord,@letters);
The first example takes a list of words and returns a list of each of those words with the letters reversed. This is done by splitting them, then reversing the resulting array, and then returning the joined array which is the word reversed. The second example takes an array of letters and returns a list of their ascii values;

Now say we want to sort an array that contains 3 columns of numbers separated by spaces. We want to sort this array on the sum of these three numbers.

The first thing we want to do is map the original array to an array with the calculated sums, as well as the original values in it.
@origarray=('0 1 2','0 0 0','-3 -2 -1','10 11 12'); @sortedarray= map{$_->[0]} sort{$a->[1] <=> $b->[1]} map{ my @cols=split(/\s+/); my $sum=$cols[0]+$cols[1]+$cols[2]; [$_,$sum]; } @origarray; foreach(@sortedarray){ print "$_\n"; }
We start by doing the basic transform within the innermost map. The current list value comes in as the default variable($_), then we split the columns, add them up, and return [$_, $sum] which contains the original value followed by the computed value for sorting on. We then sort numerically on this computed value. And then use map so the array only contains the original stuff.

This whole process is known as the Schwartzian Transform.
Here's a template for doing complex sorting
@sortedarray= map{$_->[0]} # only use one of these sort lines sort{$a->[1] <=> $b->[1]} # this one for numerical sorting sort{$a->[1] cmp $b->[1]} # this one for textual sorting map{ #calculate $computedsortval [$_,$computedsortval]; } @origarray;
This should hopefully give you a better understanding of what is going on when you need to do a complex sort, and hopefully allow you to do it right with very little hassle.

In reply to Complex sorting by vroom

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?

    What's my password?
    Create A New User
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others drinking their drinks and smoking their pipes about the Monastery: (6)
    As of 2021-01-27 20:19 GMT
    Find Nodes?
      Voting Booth?