เพิร์ล; วิธีกรองแฮชตามค่า (ระบุเงื่อนไข)

ฉันไม่เชี่ยวชาญภาษา 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;

สิ่งนี้ทำงานได้อย่างถูกต้อง - โปรดสังเกตแฮชคีย์ต่างๆ ฉันจะทราบว่า - คุณกำลังวนซ้ำคีย์ของคุณ grepping มันแล้วลบมัน มันอาจจะดีกว่าถ้า:

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