Как я изменяю это на “идиоматический” Perl?

В среде Linux Вы могли читать из/proc файловой системы.

~$ cat /proc/meminfo
MemTotal:      2076816 kB
MemFree:        130284 kB
Buffers:        192664 kB
Cached:        1482760 kB
SwapCached:          0 kB
Active:         206584 kB
Inactive:      1528608 kB
HighTotal:     1179484 kB
HighFree:       120768 kB
LowTotal:       897332 kB
LowFree:          9516 kB
SwapTotal:     2650684 kB
SwapFree:      2650632 kB
Dirty:              64 kB
Writeback:          12 kB
AnonPages:       59668 kB
Mapped:          22008 kB
Slab:           200744 kB
PageTables:       1220 kB
NFS_Unstable:        0 kB
Bounce:              0 kB
CommitLimit:   3689092 kB
Committed_AS:   263892 kB
VmallocTotal:   114680 kB
VmallocUsed:      3604 kB
VmallocChunk:   110752 kB
8
задан Martijn Pieters 2 June 2013 в 18:55
поделиться

6 ответов

У меня есть и другие комментарии, но вот первое наблюдение:

my $num_of_rows = length($self->{seq1}) + 1;
my $num_of_columns = length($self->{seq2}) + 1;

Итак $ self -> {seq1} и $ self -> {seq2} - это строки, и вы продолжаете обращаться к отдельным элементам с помощью substr . Я бы предпочел хранить их как массивы символов:

$self->{seq1} = [ split //, $seq1 ];

Вот как я бы написал это:

sub create_matrix {
    my $self = shift;

    my $matrix      = $self->{score_matrix};
    my $path_matrix = $self->{path_matrix};

    my $rows = @{ $self->{seq1} };
    my $cols = @{ $self->{seq2} };

    for my $row (0 .. $rows) {
        $matrix->[$row]->[0] =  $row * $self->{gap_cost};
        $path_matrix->[$row]->[0] = 1;
    }

    my $gap_cost = $self->{gap_cost};

    $matrix->[0] = [ map { $_ * $gap_cost } 0 .. $cols ];
    $path_matrix->[0] = [ (-1) x ($cols + 1) ];

    $path_matrix->[0]->[0] = 2;

    for my $row (1 .. $rows) {
        for my $col (1 .. $cols) {
            my $gap1 = $matrix->[$row - 1]->[$col] + $gap_cost;
            my $gap2 = $matrix->[$row]->[$col - 1] + $gap_cost;
            my $match_mismatch =
                $matrix->[$row - 1]->[$col - 1] +
                $self->get_match_score(
                    $self->{seq1}->[$row - 1],
                    $self->{seq2}->[$col - 1]
                );

            my $max = $matrix->[$row]->[$col] =
                max($gap1, $gap2, $match_mismatch);

            $path_matrix->[$row]->[$col] = $max == $gap1
                    ? -1
                    : $max == $gap2
                    ? 1
                    : 0;
            }
        }
    }
7
ответ дан 3 November 2019 в 12:49
поделиться

Одно простое изменение - использовать для такие циклы:

for my $i (0 .. $num_of_rows){
    # Do stuff.
}

Для получения дополнительной информации см. документацию Perl по циклам foreach и оператору диапазона .

8
ответ дан 3 November 2019 в 12:49
поделиться

Вместо того, чтобы разыменовать ваши двумерные массивы следующим образом:

$$path_matrix[0][0] = 2;

сделайте это:

$path_matrix->[0][0] = 2;

Кроме того, вы делаете много операторов if / then / else для сопоставления с конкретными подпоследовательностями: это могло бы быть лучше записывается как с учетом операторов (эквивалент perl5.10 переключателя C ). Прочтите об этом на perldoc perlsyn :

given ($matrix->[$row][$column])
{
    when ($seq1_gap)       { $path_matrix->[$row][$column] = -1; }
    when ($match_mismatch) { $path_matrix->[$row][$column] = 0; }
    when ($seq2_gap)       { $path_matrix->[$row][$column] = 1; }
}
7
ответ дан 3 November 2019 в 12:49
поделиться

Большая часть вашего кода манипулирует 2D-массивами. Я думаю, что самым большим улучшением будет переход на использование PDL , если вы хотите много чего делать с массивами, особенно если эффективность является проблемой. Это модуль Perl, обеспечивающий отличную поддержку массивов. Базовые процедуры реализованы на C для повышения эффективности, так что это тоже быстро.

sa Perl-модуль, обеспечивающий отличную поддержку массивов. Базовые процедуры реализованы на C для повышения эффективности, так что это тоже быстро.

sa Perl-модуль, обеспечивающий отличную поддержку массивов. Базовые процедуры реализованы на C для повышения эффективности, так что это тоже быстро.

5
ответ дан 3 November 2019 в 12:49
поделиться

Я всегда советую смотреть на CPAN , чтобы найти предыдущие решения или примеры того, как что-то делать на Perl. Вы смотрели на Algorithm :: NeedlemanWunsch ?

Документация к этому модулю включает пример сопоставления последовательностей ДНК. Вот пример использования матрицы сходства из википедии .

#!/usr/bin/perl -w
use strict;
use warnings;
use Inline::Files;                 #multiple virtual files inside code
use Algorithm::NeedlemanWunsch;    # refer CPAN - good style guide

# Read DNA sequences
my @a = read_DNA_seq("DNA_SEQ_A");
my @b = read_DNA_seq("DNA_SEQ_B");

# Read Similarity Matrix (held as a Hash of Hashes)
my %SM = read_Sim_Matrix();

# Define scoring based on "Similarity Matrix" %SM
sub score_sub {
    if ( !@_ ) {
        return -3;                 # gap penalty same as wikipedia)
    }
    return $SM{ $_[0] }{ $_[1] };    # Similarity Value matrix
}

my $matcher = Algorithm::NeedlemanWunsch->new( \&score_sub, -3 );
my $score = $matcher->align( \@a, \@b, { align => \&check_align, } );

print "\nThe maximum score is $score\n";

sub check_align {
    my ( $i, $j ) = @_;              # @a[i], @b[j]
    print "seqA pos: $i, seqB pos: $j\t base \'$a[$i]\'\n";
}

sub read_DNA_seq {
    my $source = shift;
    my @data;
    while (<$source>) {
        push @data, /[ACGT-]{1}/g;
    }
    return @data;
}

sub read_Sim_Matrix {

    #Read DNA similarity matrix (scores per Wikipedia)
    my ( @AoA, %HoH );
    while (<SIMILARITY_MATRIX>) {
        push @AoA, [/(\S+)+/g];
    }

    for ( my $row = 1 ; $row < 5 ; $row++ ) {
        for ( my $col = 1 ; $col < 5 ; $col++ ) {
            $HoH{ $AoA[0][$col] }{ $AoA[$row][0] } = $AoA[$row][$col];
        }
    }
    return %HoH;
}

__DNA_SEQ_A__
A T G T A G T G T A T A G T
A C A T G C A
__DNA_SEQ_B__
A T G T A G T A C A T G C A
__SIMILARITY_MATRIX__
-  A  G  C  T
A  10  -1  -3  -4
G  -1  7  -5  -3
C  -3  -5  9  0
T  -4  -3  0  8

И вот некоторые примеры вывода:

seqA pos: 7, seqB pos: 2  base 'G'
seqA pos: 6, seqB pos: 1  base 'T'
seqA pos: 4, seqB pos: 0  base 'A'

The maximum score is 100
0
ответ дан 3 November 2019 в 12:49
поделиться

Вы получаете несколько предложений относительно синтаксиса, но я бы также предложил более модульный подход, хотя бы по той причине, что код удобочитаем. Намного легче разобраться в коде, если вы сможете увидеть общую картину, прежде чем беспокоиться о низкоуровневых деталях.

Ваш основной метод может выглядеть так.

sub create_matrix {
    my $self = shift;
    $self->create_2d_array_of_scores;
    $self->fill_out_first_row;
    $self->fill_out_other_rows;
}

И у вас также будет несколько более мелких методов, например:

n_of_rows
n_of_cols
create_2d_array_of_scores
fill_out_first_row
fill_out_other_rows

И вы можете пойти еще дальше, определив еще более мелкие методы - геттеры, сеттеры и так далее. В этот момент ваши методы среднего уровня, такие как create_2d_array_of_scores , вообще не будут напрямую касаться базовой структуры данных.

sub matrix      { shift->{score_matrix} }
sub gap_cost    { shift->{gap_cost}     }

sub set_matrix_value {
    my ($self, $r, $c, $val) = @_;
    $self->matrix->[$r][$c] = $val;
}

# Etc.
9
ответ дан 3 November 2019 в 12:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: