通缉:更快速地检查非常大的哈希值中的所有组合

时间:2010-07-21 10:47:44

标签: perl hash

我有大约130,000个元素的哈希,我试图检查该哈希中的所有组合(130,000 x 130,000组合)。我的代码如下所示:

 foreach $key1 (keys %CNV)
 {

  foreach $key2 (keys %CNV)
  {
         if (blablabla){do something that doesn't take as long}
  }

 }

正如您所料,这需要很长时间才能运行。有谁知道更快的方法吗?非常感谢提前!!

-Abdel

编辑:更新blablabla。

嘿伙计们,感谢所有的反馈!真的很感激。我将foreach声明更改为:

for ($j=1;$j<=24;++$j)
 {
  foreach $key1 (keys %{$CNV{$j}})
  {

   foreach $key2 (keys %{$CNV{$j}})
   {
                        if (blablabla){do something}
                        }
                }
        }

哈希现在是多维的:

$CNV{chromosome}{$start,$end}

我会根据要求详细说明我正在尝试做的事情。

blablabla如下:

if  ( (($CNVstart{$j}{$key1} >= $CNVstart{$j}{$key2}) && ($CNVstart{$j}{$key1} <= $CNVend{$j}{$key2})) ||
   (($CNVend{$j}{$key1} >= $CNVstart{$j}{$key2}) && ($CNVend{$j}{$key1} <= $CNVend{$j}{$key2})) ||
   (($CNVstart{$j}{$key2} >= $CNVstart{$j}{$key1}) && ($CNVstart{$j}{$key2} <= $CNVend{$j}{$key1})) ||
   (($CNVend{$j}{$key2} >= $CNVstart{$j}{$key1}) && ($CNVend{$j}{$key2} <= $CNVend{$j}{$key1})) 
  )    

简而言之:哈希元素代表DNA的一个特定部分(所谓的“CNV”,现在认为它就像一个基因),具有开始和结束(它们是表示它们在该特定位置的整数的整数)染色体,存储在具有相同键的哈希值中:%CNVstart&amp;%CNVend)。我正在尝试检查CNV的每个组合是否重叠。如果在一个家庭中有两个重叠的元素(我的意思是一个人的家族,我的DNA已经读过;在foreach语句中还有一个for语句,让程序检查每个家庭,这使得它最后甚至更长时间),我检查它们是否也有相同的“拷贝数”(存储在具有相同键的另一个散列中)并打印出结果。

谢谢你们的时间!

7 个答案:

答案 0 :(得分:2)

听起来Algorithm::Combinatorics 可能会帮助您。它旨在提供“有效生成组合序列”。来自其文档:

  

Algorithm :: Combinatorics是一个   高效的组合发电机   序列。 ...迭代器不使用   递归,堆栈,写   在C.

您可以使用其combinations子例程从您的全套密钥中提供所有可能的2个关键组合。

另一方面,Perl 本身是用C语言编写的。所以我真的不知道这是否会有所帮助。

答案 1 :(得分:1)

也许通过使用并发?但是你必须小心你对可能的匹配所做的事情,以免出现问题。

E.g。取$ key1,将其拆分为$ key1A和§key1B。创建两个单独的线程,每个线程包含“一半的循环”。

我不确定在Perl中启动新线程究竟有多昂贵,但如果你的积极行动不需要同步,我想在匹配的硬件上你会更快。

值得一试。

答案 2 :(得分:1)

定义等等等等。

你可以这样写:

foreach $ key1(键%CNV) {

if (blah1)
{
    foreach $key2 (keys %CNV)
    {
        if (blah2){do something that doesn't take as long}
    }
}

}

此通道应为O(2N)而不是O(N ^ 2)

答案 3 :(得分:1)

问题中的数据结构不适合该问题。我们这样试试吧。

use Set::IntSpan::Fast::XS;
my @CNV;
for ([3, 7], [4, 8], [9, 11]) {
    my $set = Set::IntSpan::Fast::XS->new;
    $set->add_range(@{$_});
    push @CNV, $set;
}

# The comparison is commutative, so we can cut the total number in half.
for my $index1 (0 .. -1+@CNV) {
    for my $index2 (0 .. $index1) {
        next if $index1 == $index2; # skip if it's the same CNV
        say sprintf(
            'overlap of CNV %s, %s at indices %d, %d',
            $CNV[$index1]->as_string, $CNV[$index2]->as_string, $index1, $index2
        ) unless $CNV[$index1]->intersection($CNV[$index2])->is_empty;
    }
}

输出:

overlap of CNV 4-8, 3-7 at indices 1, 0

我们不会得到3-7, 4-8的重叠,因为它是重复的。

还有Bio::Range,但它对我来说效率不高。您一定要与bio.perl.org / open-bio人取得联系;在他们已经找到最佳算法之前,你所做的事情已经完成了一百万次。

答案 4 :(得分:1)

我想我找到了答案:-) 没有你们,不可能做到这一点。我找到了一种方法来跳过我做的大部分比较:

for ($j=1;$j<=24;++$j)
 {
            foreach $key1 (sort keys %{$CNV{$j}})
            {


                foreach $key2 (sort keys %{$CNV{$j}})
                {

                    if (($CNVstart{$j}{$key2} < $CNVstart{$j}{$key1}) && ($CNVend{$j}{$key2} < $CNVstart{$j}{$key1}))
                    {
                    next;
                    }


                    if (($CNVstart{$j}{$key2} > $CNVend{$j}{$key1}) && ($CNVend{$j}{$key2} > $CNVend{$j}{$key1}))
                    {
                    last;
                    }

        if  ( (($CNVstart{$j}{$key1} >= $CNVstart{$j}{$key2}) && ($CNVstart{$j}{$key1} <= $CNVend{$j}{$key2})) ||
           (($CNVend{$j}{$key1} >= $CNVstart{$j}{$key2}) && ($CNVend{$j}{$key1} <= $CNVend{$j}{$key2})) ||
           (($CNVstart{$j}{$key2} >= $CNVstart{$j}{$key1}) && ($CNVstart{$j}{$key2} <= $CNVend{$j}{$key1})) ||
           (($CNVend{$j}{$key2} >= $CNVstart{$j}{$key1}) && ($CNVend{$j}{$key2} <= $CNVend{$j}{$key1})) 
          )    {print some stuff out}

    }
    }
}

我做的是:

  • 为每个foreach循环排序哈希的键
  • 如果带有$ key2的CNV仍未使用$ key1到达CNV(即start2和end2都小于start1),则执行“next”
  • 并且可能是最节省时间的:如果带有$ key2的CNV用$ key1超过CNV(即start2和end2都大于end1),则结束foreach循环。

非常感谢您的时间和反馈!

答案 5 :(得分:1)

答案 6 :(得分:-1)

现在我不是一个perl战士,但根据给出的信息,它在任何编程语言中都是相同的;除非您对要检查的属性上的“哈希”进行排序并进行二进制查找,否则不会提高查找中的任何性能。

如果可以计算哈希中哪些索引具有您感兴趣的属性,也可以,但由于您没有关于这种可能性的信息,这可能不是解决方案。