我會做這樣
use strict;
use warnings;
sub get_ca_atom {
my @result = split;
return
$result[0] eq 'ATOM'
&& $result[2] eq 'CA'
&& @result > 8 ? [ @result[ 5 .. 8 ] ] :();
}
my @atoms = map get_ca_atom, <>;
while (@atoms) {
my $a = shift @atoms;
for my $b (@atoms) {
my $dist
= sqrt(($$a[1] - $$b[1])**2
+ ($$a[2] - $$b[2])**2
+ ($$a[3] - $$b[3])**2);
printf "%s\t%s\t%0.3f\n", $$a[0], $$b[0], $dist;
}
}
但在現實中我想單獨從主算法的原子內部處理,以明確並傳達儘可能好的代碼的意圖。沒有什麼比在沒有牢記這一點的情況下編寫幾個月後處理自己的代碼更糟。
use strict;
use warnings;
# handle CA ATOM record
use constant { ATOM_TAG => 0, ATOM_TYPE => 2 };
use constant ATOM_SPLICE => (5 .. 8);
use constant { NAME => 0, X => 1, Y => 2, Z => 3 };
sub get_ca_atom {
my @result = split;
return
$result[ATOM_TAG] eq 'ATOM'
&& $result[ATOM_TYPE] eq 'CA'
&& @result > (ATOM_SPLICE)[-1] ? [ @result[ATOM_SPLICE] ] :();
}
sub get_name { shift->[NAME] }
sub distance {
my ($a, $b) = @_;
sqrt( ($$a[X] - $$b[X])**2
+ ($$a[Y] - $$b[Y])**2
+ ($$a[Z] - $$b[Z])**2);
}
# end of handle CA ATOM record
my @atoms = map get_ca_atom, <>;
while (@atoms) {
my $a = shift @atoms;
for my $b (@atoms) {
my $dist = distance($a, $b);
printf "%s\t%s\t%0.3f\n", get_name($a), get_name($b), $dist;
}
}
然後,您可以隨意使用主算法。例如,上面的代碼會將所有文件內容讀入內存,這在大多數情況下都不是真正的問題。但是,如果您只想保留CA ATOMS,只需將map
更改爲以下行。
my @atoms;
while (<>) {
my $atom = get_ca_atom;
push @atoms, $atom if $atom;
}
正如你看到的,代碼的意圖慢慢地多行失蹤,但也可以是相反的時候。對代碼的主要反對意見是溝通意圖,即使這意味着更多的代碼行。特別是你不應該混合低水平和高水平,這就是我在第二個代碼示例中將distance
和get_name
分開的原因。
如果您更願意按原子順序處理原子,則可以使用以下代碼,但請注意,由於無論如何需要存儲@atoms
來計算距離,因此請注意不會節省內存。
my @atoms;
while (<>) {
my $atom = get_ca_atom;
next unless $atom;
for my $a (@atoms) {
my $dist = distance($atom, $a);
printf "%s\t%s\t%0.3f\n", get_name($a), get_name($atom), $dist;
}
push @atoms, $atom;
}
注輸出順序不同。並且還注意到我使用了next unless $atom;
而不是使用if ($atom) {
,並將塊的其餘部分封閉起來。原因是我想強調:只要不是你所期望的就跳過它。如果您想用第三種不同的輸出順序讓您感到驚喜,您可以用unshift
替換push
。
你的代碼在如此多的層面上是錯誤的,我甚至不知道從哪裏開始。 '$ argv'是什麼?爲什麼把你的輸入放在'@ ARGV'中?你認爲'@ temp'內容在下一個if語句中改變了嗎?你認爲更少的線路更好?你知道你想要輸出1653個距離嗎? – 2015-03-19 06:40:34
錯誤地我粘貼了另一個文件,我正在使用的實際文件不包含'$ argv'。現在'@ ARGV'用於命令行執行。 **是在下一個@tmp中的內容如果沒有改變(主要問題)**。我不知道代碼中行數越少越好,但我需要在上面的代碼中添加另一個計算部分,這就是爲什麼我提到過。 – Bionerd 2015-03-19 06:41:48
如果您要爲_command line execution_使用'@ ARGV',則代碼'@ARGV = <>;'不是您要查找的內容。它偶然工作,並且讓你的代碼讀者感到困惑。順便說一句,代碼應該首先與人交流,即使他們都是你,否則你可以使用機器代碼。 – 2015-03-19 06:53:40