Я изучаю вводный курс Perl и ищу предложения и отзывы о моем подходе к написанию небольшой (но сложной) программы, которая анализирует данные об атомах. Мой профессор поощряет форумы. Я не являюсь продвинутым специалистом в области подсистем или модулей Perl (включая Bioperl), поэтому, пожалуйста, ограничьте ответы до соответствующего «начального уровня», чтобы я мог понять и извлечь уроки из ваших предложений и / или кода (также ограничьте, пожалуйста, «Magic»).
Требования программы следующие:
Прочтите файл (содержащий данные об атомах) из командной строки и создайте массив записей атомов (одна запись / атом на новую строку). Для каждой записи программе потребуется сохранить:
• Серийный номер атома (столбцы 7–11)
• Трехбуквенное название аминокислоты, которой она принадлежит (столбцы 18–20)
• Три координаты атома (x, y, z) (столбцы 31–54)
• Одно- или двухбуквенное имя элемента атома (например, C, O, N, Na) (столбцы 77-78)Запрашивать одну из трех команд: freq, length, density d (d - некоторое число):
• freq - количество атомов каждого типа в файле (например, азот, натрий и т. Д. Будет отображаться следующим образом: N: 918 S: 23
• length - расстояния между координатами
• плотность d (где d - число) - программа запросит имя файла для сохранения вычислений и будет содержать расстояние между этим атомом и каждым другим атомом. Если это расстояние меньше или равно числу d, он увеличивает счетчик числа атомов, находящихся в пределах этого расстояния, если только этот счетчик не равен нулю в файле. Результат будет выглядеть примерно так:
1: 5
2: 3
3: 6
... (very big file) and will close when it finishes.
I'm looking for feedback on what I have written (and need to write) in the code below. I especially appreciate any feedback in how to approach writing my subs. I've included sample input data at the bottom.
The program structure and function descriptions as I see it:
$^W = 1; # turn on warnings
use strict; # behave!
my @fields;
my @recs;
while ( <DATA> ) {
chomp;
@fields = split(/\s+/);
push @recs, makeRecord(@fields);
}
for (my $i = 0; $i < @recs; $i++) {
printRec( $recs[$i] );
}
my %command_table = (
freq => \&freq,
length => \&length,
density => \&density,
help => \&help,
quit => \&quit
);
print "Enter a command: ";
while ( <STDIN> ) {
chomp;
my @line = split( /\s+/);
my $command = shift @line;
if ($command !~ /^freq$|^density$|length|^help$|^quit$/ ) {
print "Command must be: freq, length, density or quit\n";
}
else {
$command_table{$command}->();
}
print "Enter a command: ";
}
sub makeRecord
# Read the entire line and make records from the lines that contain the
# word ATOM or HETATM in the first column. Not sure how to do this:
{
my %record =
(
serialnumber => shift,
aminoacid => shift,
coordinates => shift,
element => [ @_ ]
);
return\%record;
}
sub freq
# take an array of atom records, return a hash whose keys are
# distinct atom names and whose values are the frequences of
# these atoms in the array.
sub length
# take an array of atom records and return the max distance
# between all pairs of atoms in that array. My instructor
# advised this would be constructed as a for loop inside a for loop.
sub density
# take an array of atom records and a number d and will return a
# hash whose keys are atom serial numbers and whose values are
# the number of atoms within that distance from the atom with that
# serial number.
sub help
{
print "To use this program, type either\n",
"freq\n",
"length\n",
"density followed by a number, d,\n",
"help\n",
"quit\n";
}
sub quit
{
exit 0;
}
# truncating for testing purposes. Actual data is aprox. 100 columns
# and starts with ATOM or HETATM.
__DATA__
ATOM 4743 CG GLN A 704 19.896 32.017 54.717 1.00 66.44 C
ATOM 4744 CD GLN A 704 19.589 30.757 55.525 1.00 73.28 C
ATOM 4745 OE1 GLN A 704 18.801 29.892 55.098 1.00 75.91 O