Перл; как отфильтровать хэш по значению (с указанием условия)

Я не очень хорошо разбираюсь в языке Perl, но столкнулся с проблемой, которую не смог решить, даже после долгих поисков в Интернете. Вкратце, у меня есть такой хэш хэшей:

my %HoH = (
    chr1 => { start => 30, end => 55, },
    chr1 => { start => 18, end => 21, },
    chr1 => { start => 30, end => 80, }
);

Я просто хотел бы найти способ отфильтровать его (я имею в виду получение нового хэша хэшей на выходе) для определенных значений. В частности, учитывая интервал, скажем, 40-60, я хочу новый хэш хэшей только с элементами, перекрывающими этот интервал.

другими словами, я хотел бы получить в качестве вывода:

my %HoH = (
    chr1 => { start => 30, end => 55, },
    chr1 => { start => 30, end => 80, }
);

В качестве первой попытки я подумал попробовать что-то вроде этого:

определить, а затем удалить все элементы с помощью "end" < 40 и: определить, а затем удалить все элементы с помощью "start" > 60.

Итак, я только что попробовал:

grep { $HoH{$_}{"end"} < 40 } keys(%HoH); 
delete $HoH{$_} for grep { $HoH{$_}{"end"} < 40} keys(%HoH);

Но сразу после первого из двух фильтров я нашел в выводе только последний элемент и вообще не понимаю, где ошибка:

hash size is 1
chr1: start=30 end=80 

распечатано со следующим:

my $len = keys %HoH;
print "hash size is $len\n";

foreach my $chr ( keys %HoH ) {
   print "$chr: ";
   for my $position ( keys %{ $HoH{$chr} } ) {
      print "$position=$HoH{$chr}{$position} ";
   }
   print "\n";
}

На этот раз это кажется мне довольно сложным, я был бы рад, если бы кто-нибудь из вас мог мне помочь.


person Francesco Gandolfi    schedule 25.06.2015    source источник
comment
У вас не может быть такой структуры данных, так как все ключи одинаковы   -  person fugu    schedule 25.06.2015


Ответы (2)


Как упоминает другой постер, ваши проблемы не в слиянии хэшей, а в том, что хэши не могут иметь повторяющиеся ключи:

use strict;
use warnings;
use Data::Dumper;

my %HoH = (
    chr1 => { start => 30, end => 55, },
    chr2 => { start => 18, end => 21, },
    chr3 => { start => 30, end => 80, }
);


grep { $HoH{$_}{"end"} < 40 } keys(%HoH); 
delete $HoH{$_} for grep { $HoH{$_}{"end"} < 40} keys(%HoH);

print Dumper \%HoH;

Это работает правильно — обратите внимание на разные хеш-ключи. Я хотел бы отметить, однако, что вы повторяете свои ключи, собираете их, а затем удаляете. Может быть лучше:

foreach my $element ( keys %HoH ) {
    delete $HoH{$element}
        unless ( $HoH{$element}{start} < 40
              or $HoH{$element}{end}   > 60 );
}

print Dumper \%HoH;

Вы можете делать то, что пытаетесь сделать, с помощью массива хэшей:

use strict;
use warnings;
use Data::Dumper;

my @AoH = (
    { start => 30, end => 55, },
    { start => 18, end => 21, },
    { start => 30, end => 80, }
);

print Dumper \@AoH;

my @filtered = grep { $_->{start} > 40 or $_->{end} < 60 } @AoH;
print Dumper \@filtered;

Примечание. В исходном примере ваши строки grep/delete делают одно и то же, и вы можете выполнить составное grep для проверки обоих условий.

person Sobrique    schedule 25.06.2015
comment
Да, вы правы, я не запомнил особенность хэшей, что они не могут хранить в себе повторяющиеся ключи. Это последнее решение кажется очень полезным и с небольшим количеством операций! большое спасибо!!!! - person Francesco Gandolfi; 25.06.2015

Проверьте свой хеш, используя Data::Dumper, и вы увидите, что у вас нет той структуры данных, о которой вы думали:

use strict;
use warnings;
use Data::Dumper;

my %HoH = (
          chr1 => {
                   start => 30,
                   end => 55,
          },
          chr1 => {
                   start => 18,
                   end => 21,
                   },
          chr1 => {
                   start => 30,
                   end => 80,
                   },
            );
            
print Dumper \%HoH;     

$VAR1 = {
          'chr1' => {
                      'start' => 30,
                      'end' => 80
                    }
        };

Что происходит, так это то, что он берет эту последнюю уникальную запись для chr1. Хэш-ключи должны быть уникальными

person fugu    schedule 25.06.2015