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

Hi,
I wanted to filter a hash. With rules like this:

1. For a hash with *keys sorted* by the second element.
2. Extract the string values (elem 4 to the end) of the hash into an array
3. If the current array is equivalent (same in size and content) with the one *just before*, ignore it.
4. Otherwise store them into a hash named 'filtered_hash'

Here is the code I attempted to write. But why it returns empty hash after filtering? How can I fix the problem?
#!/usr/bin/perl -w use strict; use Data::Dumper; use List::Compare; # The hash which I want to filter, which I manually 'ordered' # according to 2nd element of the array (184..etc), # for better visualization my %hash = ( 'GTGATCTTAGGACAAGGATAGAAATTAA' => ['1','184',7,'GACAAGG'], 'TGATCTTAGGACAAGGATAGAAATTAAG' => ['1','185',7,'GACAAGG'], 'GATCTTAGGACAAGGATAGAAATTAAGA' => ['1','186',7,'GACAAGG'], 'ACAAGGATAGAAATTAAGATGATCGTCA' => ['1','195',7,'ATCGTCA'], 'CAAGGATAGAAATTAAGATGATCGTCAT' => ['1','196',7,'ATCGTCA'], 'CAACATGCGATTACGATTACGAGTGGCG' => ['1','240',13,'GATTACG','GATTACG'], 'AACATGCGATTACGATTACGAGTGGCGC' => ['1','241',13,'GATTACG','GATTACG'], 'ATGCGATTACGATTACGAGTGGCGCTCG' => ['1','244',20,'GATTACG','GATTACG',' +GCGCTCG'], ); my %filtered_hash = filter(%hash); print Dumper \%filtered_hash; sub filter { my %hoa = @_; my %filtered_hoa; my @key = (sort {$hoa{$a}[1] <=> $hoa{$b}[1] } keys %hoa); foreach my $key (@key) { my @submt_only = @{$hoa{$key}}[3..$#{$hoa{$key}}]; my @flag = @submt_only; #Check if the current array is equiv. with *one* before my $lc = List::Compare->new(\@flag,\@submt_only); my $eq = $lc->is_LeqvlntR; if ($eq == 0 ) { #if they are not equivalent, assign them to a hash $filtered_hoa{$key} = $hoa{$key}; } else { #otherwise skip them next; } } return %filtered_hoa; }
My intended final result is:
my %filtered_hash = ( 'GTGATCTTAGGACAAGGATAGAAATTAA' => ['1','184',7,'GACAAGG'], 'ACAAGGATAGAAATTAAGATGATCGTCA' => ['1','195',7,'ATCGTCA'], 'CAACATGCGATTACGATTACGAGTGGCG' => ['1','240',13,'GATTACG','GATTACG'], 'ATGCGATTACGATTACGAGTGGCGCTCG' => ['1','244',20,'GATTACG','GATTACG',' +GCGCTCG'], );
Regards,
Edward

Replies are listed 'Best First'.
Re: Filtering a Hash
by holli (Abbot) on Apr 12, 2005 at 07:18 UTC
    You are always comparing the same two arrays, so your conditional can never be true. You "skip" everything.
    #... my @last; foreach my $key (@key) { my @submt_only = @{$hoa{$key}}[3..$#{$hoa{$key}}]; #Check if the current array is equiv. with *one* before my $lc = List::Compare->new(\@last,\@submt_only); my $eq = $lc->is_LeqvlntR; if ($eq == 0 ) { #if they are not equivalent, assign them to a hash $filtered_hoa{$key} = $hoa{$key}; } else { #otherwise skip them next; } @last = @submt_only; }


    holli, /regexed monk/
Re: Filtering a Hash
by Hena (Friar) on Apr 12, 2005 at 07:44 UTC
    Atm you are comparing array to itself. So it means that all all same, thus removed. If you want to test to one before, then something like this is needed. Note that I haven't used List module, so don't know anythign about that.
    sub filter { my %hoa = @_; my %filtered_hoa; my @key = (sort {$hoa{$a}[1] <=> $hoa{$b}[1] } keys %hoa); my @flag=(); foreach my $key (@key) { my @submt_only = @{$hoa{$key}}[3..$#{$hoa{$key}}]; #Check if the current array is equiv. with *one* before my $lc = List::Compare->new(\@flag,\@submt_only); my $eq = $lc->is_LeqvlntR; if ($eq == 0 ) { #if they are not equivalent, assign them to a hash $filtered_hoa{$key} = $hoa{$key}; } else { #otherwise skip them next; } @flag = @submt_only; } return %filtered_hoa; }
    Above code completely untested.