Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Re: Sorting an array on two computed fields

by davido (Cardinal)
on Dec 16, 2005 at 10:11 UTC ( #517196=note: print w/replies, xml ) Need Help??


in reply to Sorting an array on two computed fields

Something like this?

my @sorted = map { $_->[2] } sort { $a->[0] <=> $b->[0] or $a->[1] <=> $b->[1] } map { [ split( /-/, $_ ), $_ ] } @unsorted;

...untested, but it ought to work. The biggest problem is figuring out the best use of whitespace in making such a construct look pretty.

Update: For the record, I just tested it, and yes, it works as advertised. ;) The Schwartzian Transform isn't really a necessary part of it all, but to me, it makes it easier to read than if I had put all the splitting in the sort code block. Also, the or is used for "fall through". If the first comparison evaluates to equality, the logic falls through to the second comparison.

Update-2: Here is it without the Schwartzian Transform. ...maybe it's not that ugly after all, though as the data set grows it may become less efficient:

my @sorted = sort { my @a = split /-/, $a; my @b = split /-/, $b; $a[0] <=> $b[0] or $a[1] <=> $b[1] } @unsorted;

Dave

Replies are listed 'Best First'.
Re^2: Sorting an array on two computed fields
by blazar (Canon) on Dec 16, 2005 at 11:17 UTC
    Well, still using map, this seems a good candidate for Guttman-Rossler, and such an approach is also compatible with jesuashok's new requirement:
    #!/usr/bin/perl -l use strict; use warnings; my @data=qw/1-1 6 2-5 1-10 7 1-3 2-1/; print for map +(split)[1], sort map { (my $s=$_) =~ s/(\d+)/sprintf '%06d', $1/ge; "$s $_"; } @data; __END__

    Of course this is exclusively for illustrational purposes. In more complex or realistic situations he will have to find a suitable separator, provided that this is possible, and maybe he will have to work with index and substr instead, although pattern matching should be already optimized on fixed strings (as opposed to "real" patterns).

    Oh, and of course he must know in advance that the size of his numbers has an upper bound, which seems to be the case.

Re^2: Sorting an array on two computed fields
by tphyahoo (Vicar) on Dec 16, 2005 at 18:36 UTC
    it may become less efficient...

    It may, or it will? I guess what I am asking is, when does it pay to do the S.T. and why? Does it pay in this case? (I mean, if the data set was a lot larger?)

    UPDATE: Maybe an answer at Re: When does it pay to use the schwartzian transform?

Re^2: Sorting an array on two computed fields
by jesuashok (Curate) on Dec 16, 2005 at 10:35 UTC
    sorry for changing the requirement again what will happen if the array contains as follows:-
    my @array = ( '1-1', '6', '2-5', '1-10', '7', '1-3','2-1');
    "Keep pouring your ideas"

      ...expanding on my version "without Schwartzian Transform":

      my @sorted = sort { my @a = split /-/, $a; my @b = split /-/, $b; $a[0] <=> $b[0] or ( defined( $a[1] ) && defined( $b[1] ) and $a[1] <=> $b[1] ) } @unsorted;

      As before, the worst part is figuring out how to tab the whole thing to keep it readable. ;) You need the defined test so that fall-through doesn't occur on single-term items.

      Update: Hmm, there is a problem here though. You didn't define whether "6" should come before, after, or between "6-0" and "6-10". My solution didn't define it either, which means that the definition of the problem is inadequate, and that the solution is equally inadequate. But the point to all this is that you can hand-craft your sort routine. ...just think through what you want it to do, and craft your code. I need to get some sleep, so I'll leave you in the capable hands of the rest of the PerlMonks. :) You can do it, really. Dig in and let us know when you get stuck.


      Dave

      sorry for changing the requirement again what will happen if the array contains as follows:
      my @array = ( '1-1', '6', '2-5', '1-10', '7', '1-3','2-1');
      Well, then it depends on how you want '6' to compare to the other entries. If it's the ehm natural one, then again Sort::Naturally should be appropriate!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://517196]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (6)
As of 2022-05-24 09:23 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Do you prefer to work remotely?



    Results (82 votes). Check out past polls.

    Notices?