我有大约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语句,让程序检查每个家庭,这使得它最后甚至更长时间),我检查它们是否也有相同的“拷贝数”(存储在具有相同键的另一个散列中)并打印出结果。
谢谢你们的时间!
答案 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}
}
}
}
我做的是:
非常感谢您的时间和反馈!
答案 5 :(得分:1)
答案 6 :(得分:-1)
现在我不是一个perl战士,但根据给出的信息,它在任何编程语言中都是相同的;除非您对要检查的属性上的“哈希”进行排序并进行二进制查找,否则不会提高查找中的任何性能。
如果可以计算哈希中哪些索引具有您感兴趣的属性,也可以,但由于您没有关于这种可能性的信息,这可能不是解决方案。