Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

sorting array of array references with multiple dereferenced array elements

by onlyIDleft (Scribe)
on Sep 23, 2014 at 12:07 UTC ( [id://1101629]=perlquestion: print w/replies, xml ) Need Help??

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

@a1 = qw (ID1 len1 dom1 domlen1 seq1); @a2 = qw (ID2 len2 dom2 domlen2 seq2); @a3 = qw (ID3 len3 dom3 domlen3 seq3); $line1 = /@a1; $line2 = /@a2; $line3 = /@a3; @array =qw ($line1 $line2 $line3); # an array of array references.

I want to first sort @array by element 1 of @a1, @a2, @a3 i.e. $ID , then by element 2 - $dom, then by element 3 - $domlen, by element 4 - $seq (which would be an alphabetical sort) and finally by element [0] - $ID (another alphabetical sort).

After this sort, I want to extract the 1st element - "ID" from 1st de-referenced array, in @sorted_array

I tried something on the lines of the suggestion at : http://www.perlmonks.org/?node_id=674374 by jettero, but get an error message - I suppose because what I am trying is to sort by elements in the deferenced array of arrays- which is not what the post here is talking about, right?

Thank you in advance!

PS. Sorry about the long post title

  • Comment on sorting array of array references with multiple dereferenced array elements
  • Download Code

Replies are listed 'Best First'.
Re: sorting array of array references with multiple dereferenced array elements
by jonadab (Parson) on Sep 23, 2014 at 12:51 UTC

    If we knew in advance how many elements each of your sub-arrays were going to have, and if it were a fairly small number, we could do this with an inlined sort routine, perhaps something along these lines (assuming three elements in each sub-array):

    use Data::Dumper; print Dumper(+{ unsorted => \@array }); @array = sort { $$a[0] <=> $$b[0] or $$a[1] <=> $$b[1] or $$a[2] <=> $$b[2] } @array; use Data::Dumper; print Dumper(+{ sorted_on_first_three_elements => \@array });

    Note: This code is untested.

    This is pretty basic, and works when we don't mind listing each of the sort criteria.

    However, if we don't know how many elements there are, or if there are a whole bunch, it may be more practical to have the sort routine loop over the subarray indices from 0 to whatever, returning as soon as it has an answer. (The return values should match what <=> would return; see perlop for further information about that.)

    use Data::Dumper; print Dumper(+{ unsorted => \@array }); @array = sort { for my $i (0 .. $#a) { if (not ($$a[$i] == $$b[$i])) { return $$a[$i] <=> $$b[$i]; } } return 0; } @array; use Data::Dumper; print Dumper(+{ sorted => \@array });

    Note: This code is untested.

    Note too that the way you define the AoA feels kind of awkward, like maybe you aren't really comfortable with Perl data structures yet. That's fine, at first, but you will want to work toward being more comfortable with Perl data structures until you are able to do things like this:

    my @user = ( # [ username, fullname, authlevel, { otherinfo } ], [ 'george', 'George Jetson', $AUTH_EMPLOYEE, { supervisor => 'spaceley', pet => 'astro', } ], [ 'astro', 'Astro', $AUTH_BASIC, { supervisor => 'george', } ], [ 'hhoyt', 'Herman Hoyt', $AUTH_PROFESSOR, { supervisor => 'amcclain', department => 'theology', } + ], # and so on and so forth );
      This

      > for my $i (0 .. $#a) {

      looks wrong: $a is an array ref there is no @a involved.

      IIRC $#$a should do.

      Note This code is untested. ;)

      Cheers Rolf

      (addicted to the Perl Programming Language and ☆☆☆☆ :)

      update

      now tested! :)

      DB<109> $a=[1..10] # arrref => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] DB<110> $#$a => 9 DB<111> $a=[map [0..$_],0..3 ] # AoA => [[0], [0, 1], [0, 1, 2], [0, 1, 2, 3]] DB<112> $#{$a->[2]} => 2 DB<113> @b=(1..5) # @array => (1, 2, 3, 4, 5) DB<114> $#b => 4

      though I couldn't find a good documentation yet! :(

      Thank you for your replies, jonadab (and lanX). I have had a long 1 year break from coding, and even back then, never progressed until data structures, just until arrays and hashes. ButI will take you up on your suggestions, in the future :)

      Mneawhile, I tried your syntax, jonadab, for comparing using just one or morecriterion, BUT get the error message: "Not a SCALAR reference at test.pl line 254". Any thoughts on why this may be happening / how to fix it? Thank yoU!

      Your suggested syntax worked perfectly. Thank you jonadab. Please ignore my previous post about an error message. Thanks again!

Re: sorting array of array references with multiple dereferenced array elements
by LanX (Saint) on Sep 23, 2014 at 12:12 UTC
    The whole "code" you posted is broken, every single line is wrong.

    Please at least test before posting and spare us from guessing what some pseudo code is supposed to mean.

    Please learn how to use Data::Dumper to check your data structures.

    Cheers Rolf

    (addicted to the Perl Programming Language and ☆☆☆☆ :)

Re: sorting array of array references with multiple dereferenced array elements
by andal (Hermit) on Sep 23, 2014 at 13:33 UTC

    First of all, your code sample is incorrect.

    Second, if after sorting you are going to get only 1 field from 1 array, then it does not make any sense to sort whole array. Just go through all lines and compare the fields your need with "limit". For example, if you need to find smallest (alphabetically) value of field 0 in list of references to array, then you can use following code

    my $limit = $array[0][0]; for(my $i = 1; $i <= $#array; $i++) { my $chk = $array[$i][0]; $limit = $chk if($chk lt $limit); } print "Smallest ID is $limit\n";

    If you need to get "smallest" value from field 1, then the following code can be used

    my $limit = $array[0]; for(my $i = 1; $i <= $#array; $i++) { my $chk = $array[$i]; $limit = $chk if($chk->[0] lt $limit->[0] || ($chk->[0] eq $limit->[0] && $chk->[1] lt $limit->[1])); } print "Smallest is $limit->[1]\n";

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1101629]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (6)
As of 2024-04-19 16:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found