2017-07-26 121 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); 
    

    在用相同的间隔和相同的能量是两个间隔定义的情况下,遇到的第一个仍然保留。