【问题标题】:Can I create a hash key in perl like this (lowerR-10,UpperR-12) => 1我可以像这样在 perl 中创建一个哈希键吗 (lowerR-10,UpperR-12) => 1
【发布时间】:2012-10-21 13:59:58
【问题描述】:

我想在 perl 哈希键中创建一个哈希键,看起来像这样 (lowerR-10,UpperR-12) => 1。 这里的key是(lowerR-10,UpperR-12),其值为1。

其实我有一个这样的文件。我必须找到元素之间的重叠。

10 12

10 15

谁的输出将是

10 12 2

12 15 1

最后一列显示元素之间的重叠。 我想将计数保存在我认为密钥应该像(lowerR-10,UpperR-12)这样的哈希中。 如果有人可以就如何保存密钥提出一些新建议,那就太好了。

谢谢

【问题讨论】:

  • 这是否与Find overlap有关?
  • 是的,这与那个问题相似。我可以像那个问题($end12-$start10)中所示制作hask键

标签: perl hash perl-hash


【解决方案1】:

也许下面的程序会让您接近解决方案。

#!/usr/bin/perl
use strict;
use warnings;
use Set::IntSpan;
use Sort::Naturally;

my %data;

while (<DATA>) {
    my ($chr, @start_stop) = split; 
    $data{$chr}{$_}++ for $start_stop[0] .. $start_stop[1];
}

for my $chr (nsort keys %data) {
    my %counts;
    while (my ($range_int, $count) = each %{ $data{$chr} } ) {
        push @{ $counts{$count} }, $range_int;  
    }

    for my $count (sort {$a <=> $b} keys %counts) {
        my $set = Set::IntSpan->new(@{$counts{$count}});
        for my $run ($set->sets) {
            printf "%s %-10s count: %s\n", $chr, $run, $count;
        }
    }
    print "\n";
}

__DATA__
chr1    100    500
chr1    25      50
chr1    10       50
chr1    60       80
chr1    12       40
chr1    41       45
chr1     20      45
chr1     48      80
chr1    4   60
chr2    2   40
chr3    4   90
chr1    5   40
chr2    1   30
chr1    6   20
chr4    9   100
chr1    2   20
chr2    2   90
chr1    6   20
chr4    4   30
chr2    4   90
chr3    3   90
chr2    4   90
chr4    3   90
chr2    4   30

它产生了这个输出。

chr1 2-3        count: 1
chr1 100-500    count: 1
chr1 4          count: 2
chr1 51-59      count: 2
chr1 61-80      count: 2
chr1 5          count: 3
chr1 46-47      count: 3
chr1 60         count: 3
chr1 48-50      count: 4
chr1 6-9        count: 5
chr1 21-24      count: 5
chr1 41-45      count: 5
chr1 10-11      count: 6
chr1 25-40      count: 6
chr1 12-19      count: 7
chr1 20         count: 8

chr2 1          count: 1
chr2 2-3        count: 3
chr2 41-90      count: 3
chr2 31-40      count: 4
chr2 4-30       count: 6

chr3 3          count: 1
chr3 4-90       count: 2

chr4 3          count: 1
chr4 91-100     count: 1
chr4 4-8        count: 2
chr4 31-90      count: 2
chr4 9-30       count: 3

更新:我会尽力解释。 %counts 哈希是为外循环中的每个染色体重新创建的。键是每个编号位置的计数,例如数字 42 被看到 5 次。每个计数的值是一个匿名数组,其中包含所有出现 5 次的数字。

Set::IntSpan 用于从匿名数组(有 6,7,8,21,22,23,24,41 ,42,43,44,45 作为匿名数组中的元素)。 for my $run ($set-&gt;sets) 行获取每个运行列表中出现 5 次的数字(6-8、21-24、41-45),然后打印它们。您可以查看 Set::IntSpan 的文档,尽管它没有提供很多有用的示例,而且我无法通过网络搜索找到任何其他好的示例, 对不起。但基本上,您输入 Set::IntSpan 范围的数字,它可以为您提供浓缩的子集(6-8、21-24 等),或者根据您使用的 Set::IntSpan 方法为您提供集合中的每个单独数字访问 IntSpan 对象持有的数据。

希望这可以解决您的一些问题。 :-)

【讨论】:

  • 感谢此代码。您能否解释一下我的 $count 的这部分代码(排序 {$a $b} 键 %counts){ my $set = Set::IntSpan->new(@{$counts{$count}} );对于我的 $run_list ($set->sets) { printf "%s %-10s count: %s\n", $chr, $run_list, $count; }
  • 感谢您的解释。这对我来说是一次非常棒的学习经历:)
  • @user1763147 很高兴能帮到一些人。在这个循环中发生了很多事情,这不是最容易解释的。
  • @user1763147 您可能想要运行我发布的第二个程序,以更好地可视化散列结构及其内容。最好将输出打印到文件中,(正如我在那篇文章中指出的那样)。
【解决方案2】:

实际上,我认为基于散列的方法不适合解决这个问题。最好将其作为列表处理问题来处理。我将在 Haskell 中描述一种方法(这可以翻译成 Perl,只需要稍微多一点的代码)。

一般的方法是记录在任何给定时间有多少元素重叠。为此,我们将从元素的参数列表(开始,结束)对中构建一个“增量”列表 - 运行总数的变化。然后按照它们出现的位置对这些增量进行排序,并组合同时出现的增量。最后,保持增量的运行总和,它等于每个周期开始时重叠元素的数量(每个周期在下一个周期开始时结束)。

完整代码:

import Data.List      -- sortBy
import Data.Ord       -- comparing
import Data.Function  -- `on`

withDelta delta x = (x, delta)

episodeToDelta elements = increases ++ decreases
  where increases = map (withDelta 1    . fst) elements
        decreases = map (withDelta (-1) . snd) elements

compactDelta::[(Integer,Integer)]->(Integer,Integer)
compactDelta (x:xs) = ((fst x),(sum $ map snd (x:xs)))

adjustTotal (t, delta) ((t1, total1):rest) = (t, total1 + delta):(t1,total1):rest

deltasToRunningTotal = reverse . foldr adjustTotal [(0,0)] . reverse

noZeros = filter (\(_, d) -> d /= 0)

elementsToRunningTotal = deltasToRunningTotal . noZeros . map compactDelta . groupBy ((==) `on` fst) . sortBy (comparing fst) . elementToDelta

sample_elements = [(10,15),(5,9),(13,22),(15,19),(14,16),(3,8),(2,12),(20,22),(23,29)]

> sortBy (comparing fst) sample_elements
[(2,12),(3,8),(5,9),(10,15),(13,22),(14,16),(15,19),(20,22),(23,29)]

> episodesToRunningTotal sample_elements
[(0,0),(2,1),(3,2),(5,3),(8,2),(9,1),(10,2),(12,1),(13,2),(14,3),(16,2),(19,1),(20,2),(22,0),(23,1),(29,0)]

【讨论】:

    【解决方案3】:

    我认为显示哈希值(每个染色体的%data,%counts)可能会更好地显示每个哈希值的样子。当我不确定哈希的结构时,我经常使用 Data::Dumper。这是一个非常有用的模块。如果您运行程序(如下),它应该更好地显示哈希内容。

    您可能应该在文件中打印输出,因为(我的)终端上的视图太多 - 例如:perl your_name_program.pl &gt; junk.txt

    然后打开junk.txt查看结果。

    #!/usr/bin/perl
    use strict;
    use warnings;
    use Data::Dumper;
    use Sort::Naturally qw/ nsort /;
    
    my %data;
    
    while (<DATA>) {
        my ($chr, @start_stop) = split; 
        $data{$chr}{$_}++ for $start_stop[0] .. $start_stop[1];
    }
    
    print "Printing \%data hash as follows\n";
    print Dumper \%data;
    print "\n";
    
    for my $chr (nsort keys %data) {
        my %counts;
        while (my ($range_int, $count) = each %{ $data{$chr} } ) {
            push @{ $counts{$count} }, $range_int;  
        }
        print "Printing \%counts hash for chromosome $chr\n";
        print Dumper \%counts;
        print "\n";
    }
    
    __DATA__
    chr1    100    500
    chr1    25      50
    chr1    10       50
    chr1    60       80
    chr1    12       40
    chr1    41       45
    chr1     20      45
    chr1     48      80
    chr1    4   60
    chr2    2   40
    chr3    4   90
    chr1    5   40
    chr2    1   30
    chr1    6   20
    chr4    9   100
    chr1    2   20
    chr2    2   90
    chr1    6   20
    chr4    4   30
    chr2    4   90
    chr3    3   90
    chr2    4   90
    chr4    3   90
    chr2    4   30
    

    (目前我还不太清楚如何将 Haskell 解决方案翻译成 Perl,但稍后会进行更仔细的研究。)

    希望这能提供更清晰的画面。

    【讨论】:

    • 是的,感谢您提供这个 Data::Dumper 模块。它帮助我可视化哈希并更好地理解程序。但问题是输出文件有(10 12 3)和(13 15 2),但我希望它给出的输出是(10 12 3)和(12 15 2)。发生这种情况是因为我认为 set::intspan 根据计数构建范围。
    猜你喜欢
    • 2014-04-16
    • 1970-01-01
    • 2017-11-11
    • 2013-06-17
    • 2019-09-04
    • 1970-01-01
    • 1970-01-01
    • 2013-12-20
    • 1970-01-01
    相关资源
    最近更新 更多