[問題] 執行效率

看板Perl作者 (CW)時間11年前 (2014/03/28 17:09), 編輯推噓4(407)
留言11則, 4人參與, 最新討論串1/1
請問各位,我現在有一筆約10萬筆基因序列的資料, 部分內容如下: >Locus_41_Transcript_1/7_Confidence_0.385_Length_892 >Locus_41_Transcript_2/7_Confidence_0.385_Length_920 >Locus_41_Transcript_3/7_Confidence_0.577_Length_1466 >Locus_41_Transcript_4/7_Confidence_0.577_Length_1431 >Locus_41_Transcript_5/7_Confidence_0.538_Length_1359 >Locus_41_Transcript_6/7_Confidence_0.577_Length_1431 >Locus_41_Transcript_7/7_Confidence_0.577_Length_1431 >Locus_42_Transcript_1/1_Confidence_1.000_Length_2058 >Locus_43_Transcript_1/10_Confidence_0.312_Length_1094 >Locus_43_Transcript_2/10_Confidence_0.469_Length_1565 以locus_41為例,它有7筆資料,最後的數字是該序列的長度, 像這樣的資料,我只要取長度最大的一筆。 若是locus_42,因為只有一筆,所以不用取捨,直接使用。 我寫的程式碼如下: #!/usr/bin/env -perl -w use Bio::DB::Fasta; open my $query, "<", $ARGV[0] or die "$!"; my (%query_hash, %whole); while (my $line = <$query>) { chomp ($line); if ($line =~ /^>/) { my @line = split (/_/, $line); my $name = substr($line[0], 1)."_$line[1]"; $whole{substr($line, 1)} = "$name $line[7]"; #把所有內容皆讀入hash。 if (! exists $query_hash{$name}) { $query_hash{$name} = $line[7]; } elsif ($query_hash{$name} <= $line[7]) { $query_hash{$name} = $line[7]; #保留數字最大的一筆 } } } close $query; my $db = Bio::DB::Fasta->new($ARGV[1]); my @query_hash_result; foreach my $result (keys %query_hash) { my $query_whole = "$result $query_hash{$result}"; while (my ($key, $value) = each (%whole)) { if ($value eq $query_whole) { #重新取得完整的標題,用以取得DNA序列資料。 my $query_fasta = $db->get_Seq_by_id($key); my $query_seq = $query_fasta->seq; print ">$query_fasta\n"; print "$query_seq\n"; } } } 現在遇到的狀況是,如果我只執行上半部的程式碼,即把標題資料讀入hash, 沒什麼問題,不會用很多時間。 在%query_hash裡,大約會取得7萬筆資料。 而%whole裡,大約有14萬筆資料。 但,當我把2個hash放在一起比較,要取回完整的標題時, 整個執行的速度慢了相當多! 請問是不是我寫的程式碼裡有問題?應該要怎麼修改會比較好? 謝謝 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 140.116.25.64 ※ 文章網址: http://www.ptt.cc/bbs/Perl/M.1395997757.A.123.html

03/28 17:54, , 1F
由於第二個 while loop 會將整個 %whole 都拜訪一次
03/28 17:54, 1F

03/28 17:54, , 2F
當 %whole 很大時,時間複雜度會大幅度的提高
03/28 17:54, 2F

03/28 17:55, , 3F
如果只是需要把完整標題拿出來,可以考慮多記憶一些內容
03/28 17:55, 3F

03/28 17:56, , 4F
例如改成 $query_hash{$name} = [最大數, 完整的一行];
03/28 17:56, 4F

03/28 17:57, , 5F
這樣在跑第二個迴圈時,就不需要對 %whole 從頭查到尾
03/28 17:57, 5F

03/28 18:04, , 6F
或者把每一行的內容放在單獨的 array 裡面
03/28 18:04, 6F

03/28 18:05, , 7F
$query_hash{$name} = [最大數, 完整資料的索引];
03/28 18:05, 7F

03/28 21:57, , 8F
謝謝你的建議,我再嘗試看看。
03/28 21:57, 8F

03/29 17:13, , 9F
是Lilo大!! (膜拜
03/29 17:13, 9F

03/31 11:10, , 10F
速度差非常多,舊的用了數小時,新的瞬間秒殺!
03/31 11:10, 10F

06/01 10:09, , 11F
Lilo的思路值得學習﹐讚~~
06/01 10:09, 11F
文章代碼(AID): #1JDJmz4Z (Perl)
文章代碼(AID): #1JDJmz4Z (Perl)