簡體   English   中英

如何按鍵比較哈希值

[英]How to compare hash values by key

我有以下格式的某些輸入數據(標出了標簽):

(基因條件值)

wnt condition1  1
wnt condition2  10
wnt condition3  15
wnt condition4  -1
bmp condition1  10
bmp condition2  inf
bmp condition3  12
bmp condition4  -1
frz condition1  -12
frz condition2  -6
frz condition3  -0.3

並正在構建如下的HoH:

#!/usr/bin/perl
use warnings;
use strict; 
use File::Slurp;
use Data::Dumper;

my @data = read_file('stack.txt');

my %hash;
foreach (@data){
    chomp;
    my ($gene, $condition, $value) = (/^(\w+)\t(\w+\d)\t(-?\d+|-?inf)/);
    $hash{$gene}{$condition} = $value;
}

我想遍歷HoH,並為每個基因打印出值,前提是該基因的所有值都是正值(例如10)或負值(-3)。 在上面的數據中,我只會打印出:

frz condition1  -12
frz condition2  -6
frz condition3  -0.3

由於其他兩個基因都包含正負值的條件,因此:

wnt condition1  1
wnt condition2  10
wnt condition3  15
wnt condition4  -1 # discrepancy

bmp condition1  10
bmp condition2  inf
bmp condition3  12
bmp condition4  -1 # discrepancy 

我可以如下循環,但不確定如何在一個HoH值與該基因條件鍵組合的“下一個”值之間進行比較:

for my $gene (sort keys %hash) { 
     for my $condition (sort keys %{$hash{$gene}}) {
        my $value = $hash{$gene}{$condition};
        print "$gene\t$condition\t$value\n" if $value  =~ m/-/;  # This obviously will only print out negative values. I want to compare all values here, and if they are all positive, or all negative, print them.        
    }
}

讓我知道是否可以進一步澄清

您可以遍歷給定基因的整個值列表,並遞增正值和負值的單獨計數器,然后比較計數以查看是否存在差異,而不是孤立地比較一個值與其相鄰值。

假設您的數據符合以下方案:

'bmp' => HASH(0x7324710)
   'condition1' => 10
   'condition2' => 'inf'
   'condition3' => 12
   'condition4' => '-1'
'frz' => HASH(0x7323c78)
   'condition1' => '-12'
   'condition2' => '-6'
   'condition3' => '-0.3'
'wnt' => HASH(0x72a5c30)
   'condition1' => 1
   'condition2' => 10
   'condition3' => 15
   'condition4' => '-1'

對於問題中的最后一個代碼塊,此替換將為您提供所需的結果:

for my $gene (sort keys %hash) {
    # These variables will contain:
    # - Counts of positive and negative values
    my ($pos_vals, $neg_vals) = (0, 0);
    # - A true/false value indicating whether discrepancy exists
    my $discrepant = undef;
    # - A list of the values of all conditions for a given gene
    my @values = ();

    # Collect condition values for this gene into @values
    my @values = values %{ $hash{$gene} };

    # For each such value, test for a leading - and increment
    # the positive or negative value count accordingly
    for @values { $_ =~ m/^-/ ? $neg_vals++ : $pos_vals++ };

    # If neither counter is zero (i.e. both evaluate true), then
    # a discrepancy exists; otherwise, one doesn't -- either way,
    # we put the test result in $discrepant so as to produce a
    # cleaner test in the following if statement
    $discrepant = (($pos_vals > 0) and ($neg_vals > 0));

    # In the absence of a discrepancy...
    if (not $discrepant) {
        # iterate over the conditions for this gene and print the gene
        # name, the condition name, and the value
        # NB: this is somewhat idiomatic Perl, but you'll tend to see
        # it from time to time and it's thus worth knowing about
        print "$gene\t$_\t$hash{$gene}->{$_}\n"
          foreach sort keys %{ $hash{$gene} };
    };
}

注意 :這將正確處理正和負無窮大,但是會將零視為正,這可能不適用於您的情況。 數據中是否出現零值? 如果是這樣,應該將它們視為肯定,否定還是不作為?

此代碼通過檢查每個基因的哈希值中的所有值並在值包含負號的情況下遞增$neg來解決此問題,否則將$pos遞增。 如果正計數或負計數均為零,則所有值都具有相同的符號,並且對該基因的數據進行排序和顯示。

請注意 ,這會將inf0視為正數,這可能是所需的,也可能不是。

請注意,使用read_file是浪費資源,因為它將立即將整個文件拉入內存。 除了循環遍歷數組之外,您還可以使用while循環並逐行從文件中讀取。 使用use autodie ,無需檢查文件open調用是否成功。

use strict;
use warnings;
use autodie;

open my $fh, '<', 'stack.txt';

my %data;

while (<$fh>) {
  chomp;
  my ($gene, $condition, $value) = split /\t/;
  $data{$gene}{$condition} = $value;
}

while (my ($gene, $values) = each %data) {

  my ($pos, $neg) = (0, 0);

  ++(/-/ ? $neg : $pos) for values %$values;

  unless ($neg and $pos) {
    for my $condition (sort keys %$values) {
      printf "%s\t%s\t%s\n", $gene, $condition, $values->{$condition};
    }
  }
}

產量

frz condition1  -12
frz condition2  -6
frz condition3  -0.3
my @data = <$your_file_handle>;

my %hash;
foreach (@data){
    chomp;
    my ($gene, $condition, $value) = split; #Sorry, your regex didn't work for me, 
                                            #hence the change.
    $hash{$gene}{$condition} = $value;
}

for my $gene (sort keys %hash){
    my $values = join '', values $hash{$gene};
    my $num = %{$hash{$gene}}/1;  #Number of conditions

    #when no '-' is detected or number of '-' matches the one of conditions, print.
    say $gene if ($values !~ /-/ or $values =~ tr/-/-/ == $num); 
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM