【问题标题】:How to reference a hash of array of hashes in order to compare values如何引用散列数组的散列以比较值
【发布时间】:2018-01-02 07:45:09
【问题描述】:

我有以下数据结构:

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...),我想将子哈希(间隔符)一起比较。原谅我,我很难说这句话是对的。当然,这是数据的一个小样本。简而言之,我的目标是检测具有相同间隔的哈希数组,如果它们确实具有相同的间隔,那么我想选择具有最低能量分数的哈希数组。

【问题讨论】:

  • 以后请用Dumper(\%hash)代替Dumper(%hash)
  • 我想比较 $VAR125/$VAR126 散列中的间隔散列值”是什么意思?哈希没有“值”,你想要什么结果?
  • 例如我想比较一下垫片:CAGTGTTTTG 是否相同。然后像我一样应用一些 if 语句。
  • 您是否忘记了AGGCACC,或者您只想一次比较一个顶级哈希元素的哈希值?你想要什么结果? (如果都一样?不同值的数量?不同的值?还有什么?)
  • 是的,对于每个爸爸哈希 (hsa_circ...) 我想将婴儿哈希 (spacers) 一起比较。原谅我,我很难说这句话是对的。当然,这是数据的一个小样本。简而言之,我的目标是检测具有相同间隔的哈希数组,如果它们确实具有相同的间隔,那么我想选择具有最高能量得分的哈希数组。

标签: arrays perl hashmap perl-data-structures


【解决方案1】:

问题:每个arrayref 中可能有一组hashrefs 具有相等的spacer 值。在每个这样的组中,具有最低 energy 值的 hashref 需要确定,以替换该组。

大部分工作都是在partition_equal() 中完成的,它用相等的间隔来标识 hashref 组

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 => [ { 能量 => -3.3, 间隔 => "CAGT" }, { 能量 => -2.5, 间隔 => "GTT" }, { 能量 => -4.3, 间隔 => "AGGCACC" }, ], KB => [ { 能量 => -4.4,间隔 => “CAGT”}, { 能量 => -4.1, 间隔 => "GTT" }, { 能量 => -4.1, 间隔 => "TTG" }, ],

arrayrefs 内部的顺序没有被维护;新的数组引用首先具有具有唯一间隔值的哈希引用,然后是具有最低能量值的哈希引用(对于每个具有相同间隔值的原始组)。

子通过间隔值对输入进行排序,因此它可以通过简单地遍历排序数组并仅比较邻居来识别相等的值。这应该是相当有效的。

【讨论】:

  • 我一直在想办法做到这一点,但我很难知道如何在没有实际检查所有垫片的情况下做到这一点,并将spacer[0]spacer[1] 进行比较,然后使用 spacer[2] 等,将这些比较与 ifelsif 语句相互拼接,详细说明它们是否相等。我不确定,但不知何故,需要在不指定确切的间隔符的情况下进行比较,比如 spacer[n]、spacer[n+1]、spacer[n+2] 等,否则你需要先知道有多少我认为要比较的垫片。
  • 哦,我在想这个,我只是不知道reduce 是否可以以相同的方式处理字符串。这是一个很好的功能。
  • @MrKeystrokes 是的,reduce 是一个非常有帮助的东西。例如,大多数List::Util 函数都可以用它非常简单地编写。它需要一个列表,并通过成对比较将其简化为一个元素,该元素将“更好”与所有其他元素进行比较(根据所选标准)。 $a$b 表示正在比较的一对元素。
  • @MrKeystrokes 你描述的过程是可以的;每个元素都需要与所有元素进行比较(还有更多工作要做)。比较挑剔。诀窍是:先排序。然后你只需要看看邻居。
  • 出于好奇,在看到初始数据布局后,您会采用哪种数据结构,HoAoH 或其他?
【解决方案2】:

这样

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

print  $_ ."\n";

原来如此 $this{hash}->[array_ref]{hash]

【讨论】:

  • 不确定我是否理解这个问题......您可以通过直接访问它(如上)或通过哈希键执行循环来访问哈希元素
【解决方案3】:
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 = values(%uniq_spacer_defs);
    

    @$spacer_defs = grep { $uniq_spacer_defs{$_->{spacer}} == $_ } @$spacer_defs;
    
  • 如果两个间隔定义具有相同的间隔和相同的能量,则保留遇到的第一个。

【讨论】:

    猜你喜欢
    • 2011-07-26
    • 2010-12-31
    • 1970-01-01
    • 2017-02-09
    • 2014-05-19
    • 2014-01-27
    • 2011-08-15
    • 2014-08-31
    • 2011-07-24
    相关资源
    最近更新 更多