2017-07-26 151 views
0

我有以下數據結構:如何引用哈希值的數組的哈希值,以比較值

my %hash = (
    'hsa_circ_0024017|chr11:93463035-93463135+|NM_033395|KIAA1731 FORWARD' => [ 
     { 
      'energy' => '-4.3', 
      'spacer' => 'AGGCACC', 
      'end' => '97', 
      'start' => '81' 
     } 
    ], 
    'hsa_circ_0067224|chr3:128345575-128345675-|NM_002950|RPN1 FORWARD' => [ 
     { 
      'energy' => '-4.4', 
      'spacer' => 'CAGT', 
      'end' => '17', 
      'start' => '6' 
     }, 
     { 
      'energy' => '-4.1', 
      'spacer' => 'GTT', 
      'end' => '51', 
      'start' => '26' 
     }, 
     { 
      'energy' => '-4.1', 
      'spacer' => 'TTG', 
      'end' => '53', 
      'start' => '28' 
     } 
    ], 
    ... 
); 

如何訪問我的哈希值的內容能夠在一個循環中的內容比較?

對於每個父散列(hsa_circ ...)我想比較孩子哈希(間隔)在一起。原諒我,我正在努力說出這個權利。這當然是一小部分數據。簡而言之,我的目標是檢測具有相同間隔符的散列陣列,如果他們確實具有相同的間隔符,那麼我想要選擇具有最低能量得分的散列數組。

+3

未來,請求使用'Dumper(\%hash)'而不是'Dumper(%hash)' – ikegami

+0

「*我想比較$ VAR125/$中的間隔哈希值VAR126哈希與對方*「是什麼意思?哈希沒有「有價值」,你想要什麼結果? – ikegami

+0

例如我想比較一下墊片:** CAGT **,** GTT **和** TTG **,看看它們是否相同。然後像我這樣應用一些if語句。 –

回答

1

問題:有可能在每個hashrefs組數組引用與等於間隔值。在每個這樣的組中,需要標識具有最低能量值 的hashref以替換該組。

的大部分工作是在partition_equal()完成,標識與相等間隔

use warnings; 
use strict; 
use List::Util qw(reduce); 
use Data::Dump qq(dd); 

# Test data: two groups of equal-spacer hashrefs, in the first array only 
my %hash = ( 
    kA => [ 
     { 'energy' => -4.3, 'spacer' => 'AGGCACC' }, 
     { 'energy' => -2.3, 'spacer' => 'AGGCACC' }, 
     { 'energy' => -3.3, 'spacer' => 'CAGT' }, 
     { 'energy' => -1.5, 'spacer' => 'GTT' }, 
     { 'energy' => -2.5, 'spacer' => 'GTT' }, 
    ], 
    kB => [ 
     { 'energy' => -4.4, 'spacer' => 'CAGT' }, 
     { 'energy' => -4.1, 'spacer' => 'GTT' }, 
     { 'energy' => -4.1, 'spacer' => 'TTG' }, 
    ], 
); 
#dd \%hash; 

for my $key (keys %hash) { 
    my ($spv, $unique) = partition_equal($hash{$key}); 
    next if not $spv; 
    # Extract minimum-energy hashref from each group and add to arrayref 
    # $unique, so that it can eventually overwrite this key's arrayref 
    foreach my $spacer (keys %$spv) { 
     my $hr_min = reduce { 
      $a->{energy} < $b->{energy} ? $a : $b 
     } @{$spv->{$spacer}}; 
     push @$unique, $hr_min; 
    } 
    # new: unique + lowest-energy ones for each equal-spacer group 
    $hash{$key} = $unique if keys %$spv; 
}  
dd \%hash; 

# Sort array and compare neighbouring elements (hashrefs) 
sub partition_equal { 
    my $ra = shift; 
    my @sr = sort { $a->{spacer} cmp $b->{spacer} } @$ra; 

    # %spv: spacer value => [ hashrefs with it ], ... 
    # @unique: hasrefs with unique spacer values  
    my (%spv, @unique); 

    # Process first and last separately, to not have to test for them 
    ($sr[0]{spacer} eq $sr[1]{spacer}) 
     ? push @{$spv{$sr[0]{spacer}}}, $sr[0] 
     : push @unique, $sr[0]; 
    for my $i (1..$#sr-1) { 
     if ($sr[$i]{spacer} eq $sr[$i-1]{spacer} or 
      $sr[$i]{spacer} eq $sr[$i+1]{spacer}) 
     { 
      push @{$spv{$sr[$i]{spacer}}}, $sr[$i] 
     } 
     else { push @unique, $sr[$i] } 
    } 
    ($sr[-1]{spacer} eq $sr[-2]{spacer}) 
     ? push @{$spv{$sr[-1]{spacer}}}, $sr[-1] 
     : push @unique, $sr[-1]; 

    return if not keys %spv; 
    return \%spv, \@unique; 
} 

輸出

 
kA => [ 
     { energy => -3.3, spacer => "CAGT" }, 
     { energy => -2.5, spacer => "GTT" }, 
     { energy => -4.3, spacer => "AGGCACC" }, 
     ], 
kB => [ 
     { energy => -4.4, spacer => "CAGT" }, 
     { energy => -4.1, spacer => "GTT" }, 
     { energy => -4.1, spacer => "TTG" }, 
     ], 

內部arrayrefs的次序並不維持hashref基;新的arrayref具有唯一間隔值的第一個hashrefs,然後是具有最低能量值的那些(對於具有相同間隔值的每個原始組)。

子排序通過間隔值輸入,以便它可以通過簡單地遍歷排序後的數組並僅比較鄰居來識別相等的數據。這應該是合理有效的。

+0

我一直在想辦法做到這一點,但我我們正努力去研究如何去做,而實際上並沒有通過所有的間隔物,並且比較'spacer [0]'和'spacer [1]',然後用間隔物[2]等,這些比較與_if_和_elsif_聲明詳細說明如果他們平等或不相干應該怎麼做。我不確定,但不知怎的,比較需要在沒有指定確切的間距的情況下發生,例如spacer [n],spacer [n + 1],spacer [n + 2]等。否則,您需要知道多少我想,可以比較一些間隔物。 –

+0

哦,我在想這個,我只是不知道'reduce'是否可以用同樣的方式處理字符串。它是一個簡潔的函數。 –

+0

@MKKeystrokes是的,'減少'是一件非常有趣的事情。例如,大多數'List :: Util'函數都可以很簡單地寫出來。它需要一個列表,並通過成對比較將其縮減爲一個元素,將「更好」與所有其他元素進行比較(根據所選標準)。 '$ a'和'$ b'表示被比較的元素對。 – zdim

0

喜歡這個

$_=$hash{'hsa_circ_0024017|chr11:93463035-93463135+|NM_033395|KIAA1731 FORWARD'}->[0]{energy}; 

print $_ ."\n"; 

所以它的 $此{哈希} - > [ARRAY_REF] {散列]

+0

不知道我是否理解這個問題...你可以通過直接訪問它(如上所述)或通過散列鍵進行循環訪問散列元素 – hoffmeister

0
for my $line (keys(%by_line)) { 
    my $spacer_defs = $by_line{$line}; 
    ... 
} 

for my $spacer_defs (values(%by_line)) { 
    ... 
} 

將讓你(參考到)針對每行的(參考)間隔定義的陣列 反過來。然後,您可以編輯如下數組:

my %uniq_spacer_defs; 
    for my $spacer_def (@$spacer_defs) { 
     my $spacer = $spacer_def->{spacer}; 
     $uniq_spacer_defs{$spacer} = $spacer_defs 
     if !$uniq_spacer_defs{$spacer} 
     || $uniq_spacer_defs{$spacer}{energy} < $spacer_def->{energy}; 
    } 

    @$spacer_defs = values(%uniq_spacer_defs); 

注:

  • 的 「間隔定義」 的順序可能會改變。如果這是一個問題,

    @$spacer_defs = grep { $uniq_spacer_defs{$_->{spacer}} == $_ } @$spacer_defs; 
    
  • 更換

    @$spacer_defs = values(%uniq_spacer_defs); 
    

    在用相同的間隔和相同的能量是兩個間隔定義的情況下,遇到的第一個仍然保留。