Как найти столбец данных вместо позиции символа НЕ используя цикл для поиска в Perl и Bash? - PullRequest
0 голосов
/ 23 апреля 2019

То, что я хочу знать, это как найти расположение атома H (в виде номера столбца вместо номера символа) в строке / массиве, используя PERL или Bash?Я пытался избежать ненужных циклов поиска в H, потому что мои данные содержат более миллиона строк.

У меня есть данные исследований, показанные ниже

FRAM_#     20000000      5000000(fs)  CN= 1 PRMRYTGT     16652      O      16654      H  1.036      8140     CA  2.586      7319     AL  1.963

Где присутствуют атомы O, H, CA и AL.Первый атом представляет собой целевой атом кислорода, а остальные являются соседями, которые связаны с целевым кислородом.За исключением первого атома (кислорода), целое число перед каждым атомом является идентификатором атома, а число с плавающей запятой после него является длиной связи с первым атомом O (ID = 16652).

$line = 'FRAM_#     20000000      5000000(fs)  CN= 1    PRMRYTGT     16652'
        . '      O     16654      H  1.036      8140     CA  2.586'
        . '     7319     AL  1.963';
@values = split(/\s+/, $line);
my $bondlength;
my $neighbor_ID;
for (my $i = 10; $i <= $#values; $i = $+3) {
  if ($values[$i] eq 'H') {
    $neighbor_ID = $values[$i-1];
    $bondlength = $values[$i+1];
  } else {
    next;
  }

Я могу использовать цикл для поиска позиции H в массиве @values.Тем не менее, есть ли другой способ (не цикл), например, регулярные выражения или сценарии BASH, чтобы получить положение H в массиве?Я очень признателен, если бы вы могли дать мне дополнительное предложение и помощь.

Я хочу найти водородную связь (длина связи более 1,5 ангстрем) между Н и целевым кислородом.Итак, я должен получить ID атома Н и соответствующую длину связи.Итак, во-первых, мне нужно найти местоположение H. А затем найти идентификатор атома и соответствующую длину связи.И тогда я могу сделать дальнейший анализ данных.

ПРИМЕЧАНИЕ. У меня больше 1 млн строк данных, поэтому я должен учитывать эффективность кода.H - мой целевой атом в этом примере.В строках данных количество H может быть различным.

Ответы [ 4 ]

1 голос
/ 24 апреля 2019

perl: используйте firstidx из List::MoreUtils

use List::MoreUtils  qw/ firstidx /;

my $line = '...';
my @values = split ' ', $line;
my $h_idx = firstidx {$_ eq 'H'} @values;
print "H appears at index $h_idx\n";

Это будет использовать петлю под капотом . Я не понимаю, как вы можете избежать этого. Если ваш список отсортирован, вы можете использовать бинарный поиск, но ваш список не отсортирован.

С другой стороны, вам вообще не нужно разбивать свою строку на список, что должно сэкономить вам некоторое время:

my ($neighbour_id, $bond_length) = $line =~ /(\d+) \s+ H \s+ (\S+)/x;
return $neighbour_id if $bond_length > 1.5;
0 голосов
/ 23 апреля 2019

Вот ваш код, слегка переформатированный для удобства чтения (пробелов не хватает!)

$line = "FRAM_#     20000000      5000000(fs)  CN= 1  PRMRYTGT     16652      O      16654      H  1.036      8140     CA  2.586      7319     AL  1.963";

@values = split(/\s+/, $line);

my ($bondlength, $neighbor_ID);

for (my $i = 10; $i <= $#values; $i += 3) {
  if ($values[$i] eq 'H') {
    $neighbor_ID = $values[$i-1];
    $bondlength = $values[$i+1];
  }
  else {
    next;
  }
}

Предложение else в вашем цикле совершенно не нужно. В любом случае цикл просто перейдет к следующей итерации.

Одна очевидная оптимизация - перестать смотреть, как только вы найдете атом водорода. Итак, ваш код будет выглядеть так:

$line = "FRAM_#     20000000      5000000(fs)  CN= 1  PRMRYTGT     16652      O      16654      H  1.036      8140     CA  2.586      7319     AL  1.963";

@values = split(/\s+/, $line);

my ($bondlength, $neighbor_ID);

for (my $i = 10; $i <= $#values; $i = $+3) {
  if ($values[$i] eq 'H') {
    $neighbor_ID = $values[$i-1];
    $bondlength = $values[$i+1];
    last; # stop looking once you've found it
  }
}

Я не знаю, достаточно ли оптимизации для решения всех ваших проблем, но это только начало.

0 голосов
/ 23 апреля 2019

Не ясно, каков именно ожидаемый результат для данного ввода. Если это пара цифр до и после буквы H, будет сделано следующее.

sed -E 's/.*\s+(\S+)\s+H\s+(\S+)\s.*/\1,\2/' < input.txt

Пример ввода:

FRAM_#     20000000      5000000(fs)  CN= 1 PRMRYTGT     16652      O      16654      H  1.036      8140     CA  2.586      7319     AL  1.963

Пример вывода:

16654,1.036
0 голосов
/ 23 апреля 2019
open(FH, "data.txt") or die "Can’t open data.txt: $!";

while(<FH>)
{
 if (@d=/\bO\s+(\d+)\s+H\s+(1\.[5-9]\d*|[2-9][\d.]*)/) {print "$_\n" for @d}
$ID=$d[0]
$len=$d[1]
}

каждая строка данных приводит только к идентификатору, указанному в $d[0] и длине связи в $d[1], если больше / равно 1,5, из @d массива

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...