Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Complex sort of array of hashes into an array of arrays

by BioJL (Initiate)
on Nov 23, 2010 at 15:08 UTC ( [id://873227]=perlquestion: print w/replies, xml ) Need Help??

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

Hi,

I'm a newbie in perl (also in programming), so I'll try to explain myself... I have an array of hashes with the following structure

$matrix[0]{A} = 22

...

$matrix[1]{C} = 30

...

...

[A->22, C->51, G->7, T->0]

[A->9, C->30, G->0, T->2]

[and so on ]

I want to sort each row in another array of arrays by the values of each hash, but keeping the information of the letter. For instance:

@sorted[][]

[ 51 22 7 0 C A G T ]

[ 30 9 2 0 C A T G ]

...

So i can relate 51 with C, 22 with C, etc.

Thanks in advance!

I tried to do the thing that kennethk proposes but i got lost in the syntax because It's a hash into an array.

@sorted = sort { {$a} <=> {$b} } keys @matrix[$pos]{};

Replies are listed 'Best First'.
Re: Complex sort of array of hashes into an array of arrays
by kennethk (Abbot) on Nov 23, 2010 at 15:23 UTC
    What have you tried? What didn't work? Shown effort is appreciated around the monastery, and it helps us gauge your experience level so we can tailor our answers. See How do I post a question effectively?. As well, note how your index on $matrix[1]{C} = 30 got linkified. This is because you did not wrap your code in <code> tags. See Writeup Formatting Tips.(Fixed, thank you)

    You appear to want to sort your keys in descending numeric order. This can be accomplished with sort combined with the block {$b <=> $a}. For adding keys, I would likely use reverse to invert the hash (How do I look up a hash element by value?) and then push them onto the end of the array rather than trying to keep track of indices to do it all at once. If you are not familiar with dealing with complex data structures, a read through perlreftut would likely be helpful. Provide us with some templated code (even if it doesn't work right), and we can help guide you to your solution.

Re: Complex sort of array of hashes into an array of arrays
by VinsWorldcom (Prior) on Nov 23, 2010 at 15:40 UTC

    The following prints exactly what you asked for (as I read it). I'm not sure this is what you mean though.

    use strict; use warnings; my @matrix = ( {A => 22, C => 51, G => 7, T => 0}, {A => 9, C => 30, G => 0, T => 2}, ); for my $h (@matrix) { my @temp; print "[ "; for my $k (sort {$h->{$b} <=> $h->{$a}} (keys(%{$h}))) { print "$h->{$k} "; push @temp, $k } print "@temp ]\n" }

    UPDATE: Modified to address your updates above. Note this *PRINTS* what you want, it doesn't put the date into a new structure - you can figure that part out.

    use strict; use warnings; my @matrix = ( {A => 4, C => 0, G => 13, T => 0}, {A => 5, C => 0, G => 12, T => 0}, {A => 15, C => 0, G => 2, T => 0}, {A => 0, C => 17, G => 0, T => 0}, ); for my $h (0..$#matrix) { my @temp; print "[ $h "; for my $k (sort {$matrix[$h]->{$b} <=> $matrix[$h]->{$a}} (keys(%{ +$matrix[$h]}))) { print "$matrix[$h]->{$k} "; push @temp, $k } print "@temp ]\n" }
Re: Complex sort of array of hashes into an array of arrays
by jethro (Monsignor) on Nov 23, 2010 at 16:23 UTC
    Somewhat related: Take a look at Data::Dumper. With it you can print out your data structures comfortably (great for debugging), and this is also the prefered method to tell others (for example perlmonks) what data structures you have or want to have.

    Just try it out, it is already included in your perl:

    use Data::Dumper; print Dumper(\%matrix);
Re: Complex sort of array of hashes into an array of arrays
by chrestomanci (Priest) on Nov 23, 2010 at 15:27 UTC

    I have read your post about a dozen times, and I still can't understand what you are trying to do, and if I can't then most other monks here won't either

    I think you need to explain a bit further what you are trying to achieve. Can I suggest you post 20 lines or so of raw data, and then the same data sorted by hand in the way you want.

    There is almost certainly a simple solution to this using sort, and passing a code block to it.

    my @sorted = sort { $a->{$foo}[$bar] <=> $b->{$foo}[$bar] } @raw_data;

      I have the following input data, showing only a few lines:

      Pos A C G T 0 4 0 13 0 1 5 0 12 0 2 15 0 2 0 3 0 17 0 0

      I stored that data into an array of hashes called @matrix. For instance $matrix[0]{A}=4 and so on.

      I want to sort each line from highest frequency to lowest frequency and store it in another array of arrays, but I also need to remember wich letter corresponds to each number

      I thought it would be a good idea to store the nucleotide order at the end of the array, here is an example with the first lines that i would like to obtain:

      First number is original position. I put it there because then i would like to sort the matrix by the top most score of each row.

      [0 13 4 0 0 G A C T] [1 12 5 0 0 G A C T] [2 15 2 0 0 A G C T] [3 17 0 0 0 C A G T]

      I hope it's more clear now...

        Note that your data above is not the same as your original posting - you've added another entry to the start of each row. Do you have code that already reads in your data and generates the actual data structure, or are you just working off input files? Posting code that generates the desired structure makes sure we are working with the same beast you are working with and makes our lives easier. There is no good reason for us to try and guess at what you have and what you need - we are doing you a favor.
        my @sorted = sort { $$a[1] <=> $$b[1]; } map { my $index = $_; my $entry = $data[$index]; my @scores = sort { $$entry{$b} <=> $$entry{$a} keys %$entry; [ $index, @scores, (map { $$entry{$_} } @scores), ] } 0 .. $#data;
Re: Complex sort of array of hashes into an array of arrays
by anonymized user 468275 (Curate) on Nov 23, 2010 at 16:17 UTC
    I would also use a sort block but keeping your starting point and required output structure intact and after your second post it looks like this:
    my @result=(); for (my $i=0; $i<=$#matrix;$i++){ my @resline = ( $i+1 ); my @keys = (); for my $k ( sort { $matrix[$i]{$b} <=> $matrix[$i]{$a} } keys %{ $ +matrix[$i] } ) { push @keys, $k; push @resline, $matrix[$i]{$k}; } push @resline, @keys; push @result, \@resline; # nb. pushing the reference not the array + this time }

    One world, one people

Re: Complex sort of array of hashes into an array of arrays
by 7stud (Deacon) on Nov 24, 2010 at 01:24 UTC
    use strict; use warnings; use 5.010; my @hrefs = ( {a=>22, g=>7, c=>51, t=>0}, {a=>9, t=>2, c=>30, g=>0}, ); my @final_data; #Extract each hash from the array: for my $hash_ref (@hrefs) { my %hash = %{$hash_ref}; #Convert the hash into an array of key/value pairs: my @pairs = map [$hash{$_}, $_], keys %hash; #Sort the key/value pairs based on the number: my @sorted_pairs = reverse sort {$a->[0] <=> $b->[0]} @pairs; #Add the numbers to one array and the corresponding #letters to another array: my (@numbers, @letters); for my $pair_ref (@sorted_pairs) { push @numbers, $pair_ref->[0]; push @letters, $pair_ref->[1]; } #Add the letters to the end of the numbers array: push @numbers, @letters; say "@numbers"; #Collect the data in an array: push @final_data, \@numbers; } print "\n"; use Data::Dumper; print Dumper(\@final_data); --output:-- 51 22 7 0 c a g t 30 9 2 0 c a t g $VAR1 = [ [ 51, 22, 7, 0, 'c', 'a', 'g', 't' ], [ 30, 9, 2, 0, 'c', 'a', 't', 'g' ] ];

      Thank you all for are your answers, I think all of them works for me but more important I learned a lot about sorting and data structures.

      I am working now on adapting that code to my (bigger) program.

      I will post that part of the code once done if you think it may be useful for anyone.

        I have a previous code reading the matrix from a file and storing it in the @matrix array of hashes with the structure I showed in the previous post.

        Sorting each row of the original matrix by nucleotide frequency and copying it to another matrix keeping the original position of the row, the nucleotides frequencies and then the nucleotides corresponding to the frequencies in the same order. [OriPos, F1, F2, F3, F4, N1, N2, N3, N4]where F1 is the most frequent nucleotide and N1 is his corresponding letter.

        sub sortmatrix(){ for (my $i=0; $i<=$#matrix;$i++){ my @resline = ( $i+1 ); my @keys = (); for my $k ( sort { $matrix[$i]{$b} <=> $matrix[$i]{$a} } keys %{ $ +matrix[$i] } ) { push @keys, $k; push @resline, $matrix[$i]{$k}; } push @resline, @keys; push @sorted, \@resline; # nb. pushing the reference not the array + this time }

        Sorting the rows of the matrix by the most frequent nucleotide column, then the 2nd, 3rd, 4th and last by original position

        @sorted = sort { $b->[1] <=> $a->[1] || $b->[2] <=> $a->[2] || $b->[3] <=> $a->[3] || $b->[4] <=> $a->[4] || $a->[0] <=> $b->[0]; } @sorted; } use Data::Dumper; print Data::Dumper->Dump([ \@sorted ],[ qw/ *matrix / ]),"\n";

        And here i get my matrix completely sorted :)

        @sortedmatrix = ( [ 4, 17, 0, 0, 0, 'C', 'A', 'T', 'G' ], [ 5, 17, 0, 0, 0, 'A', 'T', 'C', 'G' ], [ 6, 17, 0, 0, 0, 'T', 'A', 'C', 'G' ], [ 7, 17, 0, 0, 0, 'G', 'A', 'T', 'C' ], [ 9, 17, 0, 0, 0, 'C', 'A', 'T', 'G' ], [ 10, 17, 0, 0, 0, 'C', 'A', 'T', 'G' ], [ 11, 17, 0, 0, 0, 'G', 'A', 'T', 'C' ], [ 12, 17, 0, 0, 0, 'G', 'A', 'T', 'C' ], [ 14, 17, 0, 0, 0, 'C', 'A', 'T', 'G' ], [ 15, 17, 0, 0, 0, 'A', 'T', 'C', 'G' ], [ 16, 17, 0, 0, 0, 'T', 'A', 'C', 'G' ], [ 17, 17, 0, 0, 0, 'G', 'A', 'T', 'C' ], [ 3, 15, 2, 0, 0, 'A', 'G', 'T', 'C' ], [ 13, 15, 2, 0, 0, 'G', 'A', 'T', 'C' ], [ 18, 15, 2, 0, 0, 'T', 'C', 'A', 'G' ], [ 1, 13, 4, 0, 0, 'G', 'A', 'T', 'C' ], [ 8, 13, 4, 0, 0, 'C', 'T', 'A', 'G' ], [ 19, 13, 4, 0, 0, 'C', 'T', 'A', 'G' ], [ 2, 12, 5, 0, 0, 'G', 'A', 'T', 'C' ], [ 20, 7, 7, 2, 0, 'T', 'C', 'G', 'A' ] );

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (3)
As of 2024-04-19 05:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found