Wie schreibe ich einen einzeiligen Code (oder weniger Zeilencode in der Befehlszeile) dieses Codes in Perl um?

StackOverflow https://stackoverflow.com/questions/5402405

  •  28-10-2019
  •  | 
  •  

Frage

Ich habe einen Code wie diesen:

#!/usr/bin/perl
use strict;
use warnings;      
my %proteins = qw/
    UUU F UUC F UUA L UUG L UCU S UCC S UCA S UCG S UAU Y UAC Y UGU C UGC C UGG W
    CUU L CUC L CUA L CUG L CCU P CCC P CCA P CCG P CAU H CAC H CAA Q CAG Q CGU R CGC R CGA R CGG R
    AUU I AUC I AUA I AUG M ACU T ACC T ACA T ACG T AAU N AAC N AAA K AAG K AGU S AGC S AGA R AGG R
    GUU V GUC V GUA V GUG V GCU A GCC A GCA A GCG A GAU D GAC D GAA E GAG E GGU G GGC G GGA G GGG G
    /;
open(INPUT,"<dna.txt");
while (<INPUT>) {    
    tr/[a,c,g,t]/[A,C,G,T]/;
    y/GCTA/CGAU/;    
    foreach my $protein (/(...)/g) {
        if (defined $proteins{$protein}) {
        print $proteins{$protein};
        }
}
}
close(INPUT);

Dieser Code bezieht sich auf die Antwort meiner anderen Frage: DNA zu RNA und Proteine ​​mit Perl erhalten

Die Ausgabe des Programms ist:

SIMQNISGREAT

Wie kann ich diesen Code mit Perl umschreiben, er wird auf der Befehlszeile ausgeführt und mit weniger Code (wenn möglich mit einem Zeilencode) neu geschrieben?

PS 1: dna.txt sieht so aus:

TCATAATACGTTTTGTATTCGCCAGCGCTTCGGTGT

PS 2: Wenn der Code weniger Zeilen enthält, wird das Schreiben akzeptiert my %proteins Variable in eine Datei.

War es hilfreich?

Lösung

Jemand (@kamaci) hat in einem anderen Thread meinen Namen gerufen.Dies ist das Beste, was mir einfällt, wenn ich die Proteintabelle in der Befehlszeile behalte:

perl -nE'say+map+substr("FYVDINLHL%VEMKLQL%VEIKLQFYVDINLHCSGASTRPWSGARTRP%SGARTRPCSGASTR",(s/GGG/GGC/i,vec($_,0,32)&101058048)%63,1),/.../g' dna.txt

(Shell-Anführungszeichen, für Windows-Anführungszeichenaustausch ' Und " Figuren).Diese Version markiert ungültige Codons mit %, das können Sie wahrscheinlich durch Hinzufügen beheben =~y/%//d an einer geeigneten Stelle.

Hinweis:Dadurch werden 6 Bits aus der rohen ASCII-Kodierung eines RNA-Triples herausgegriffen, was 64 Codes zwischen 0 und 101058048 ergibt;Um einen String-Index zu erhalten, reduziere ich das Ergebnis modulo 63, aber dadurch entsteht eine doppelte Zuordnung, die leider zwei verschiedene Proteine ​​codieren musste.Der s/GGG/GGC/i ordnet einen von ihnen einem anderen zu, der das richtige Protein kodiert.

Beachten Sie auch die Klammern vor dem % Betreiber, der beide Isolieren Sie die , Operator aus der Argumentliste von substr Und den Vorrang festlegen & vs %.Wenn Sie das jemals im Produktionscode verwenden, sind Sie ein schlechter, schlechter Mensch.

Andere Tipps

Die einzigen Änderungen, die ich empfehlen würde, sind die Vereinfachung Ihrer while-Schleife:

while (<INPUT>) {
    tr/acgt/ACGT/;
    tr/GCTA/CGAU/;
    foreach my $protein (/(...)/g) {
        if (defined $proteins{$protein}) {
            print $proteins{$protein};
        }
    }
}

Da y und tr Synonyme sind, sollten Sie nur eines davon verwenden.Ich denke, tr liest sich besser als y, also habe ich tr ausgewählt.Außerdem haben Sie sie sehr unterschiedlich genannt, aber dies sollte der gleiche Effekt sein und nur die Buchstaben erwähnen, die Sie tatsächlich ändern.(Alle anderen Zeichen wurden auf sich selbst übertragen. Dadurch ist es viel schwieriger zu erkennen, was tatsächlich geändert wird.)

Möglicherweise möchten Sie den open(INPUT,"<dna.txt"); und die entsprechenden close(INPUT);-Zeilen entfernen, da dies die Verwendung Ihres Programms in Shell-Pipelines oder mit anderen Eingabedateien erheblich erschwert.Aber es liegt an Ihnen, ob die Eingabedatei immer dna.txt ist und niemals etwas anderes, das ist in Ordnung.

#!/usr/bin/perl
%p=qw/UUU F UUC F UUA L UUG L UCU S UCC S UCA S UCG S UAU Y UAC Y UGU C UGC C UGG W
CUU L CUC L CUA L CUG L CCU P CCC P CCA P CCG P CAU H CAC H CAA Q CAG Q CGU R CGC R CGA R CGG R
AUU I AUC I AUA I AUG M ACU T ACC T ACA T ACG T AAU N AAC N AAA K AAG K AGU S AGC S AGA R AGG R
GUU V GUC V GUA V GUG V GCU A GCC A GCA A GCG A GAU D GAC D GAA E GAG E GGU G GGC G GGA G GGG G/;
$_=uc<DATA>;y/GCTA/CGAU/;map{print if$_=$p{$_}}/(...)/g
__DATA__
TCATAATACGTTTTGTATTCGCCAGCGCTTCGGTGT

Puh.Das Beste, was ich mir vorstellen kann, zumindest so schnell.Wenn Sie sicher sind, dass die Eingabe immer bereits in Großbuchstaben erfolgt, können Sie den uc auch löschen und zwei weitere Zeichen speichern.Wenn die Eingabe immer dieselbe ist, können Sie sie sofort dem $_ zuweisen, anstatt sie von irgendwoher zu lesen.

Ich muss wohl nicht sagen, dass dieser Code nicht in Produktionsumgebungen oder an anderen Orten als Spaß verwendet werden sollte.Bei der eigentlichen Programmierung gewinnt die Lesbarkeit fast immer über die Kompaktheit.

Einige andere Versionen, die ich in den Kommentaren erwähnt habe:

% p und die DNA aus Dateien lesen:

#!/usr/bin/perl
open A,"<p.txt";map{map{/(...)/;$p{$1}=chop}/(... .)/g}<A>;
open B,"<dna.txt";$_=uc<B>;y/GCTA/CGAU/;map{print if$_=$p{$_}}/(...)/g

Von der Shell mit perl -e:

perl -e 'open A,"<p.txt";map{map{/(...)/;$p{$1}=chop}/(... .)/g}<A>;open B,"<dna.txt";$_=uc<B>;y/GCTA/CGAU/;map{print if$_=$p{$_}}/(...)/g'

Auf die meisten Dinge wurde bereits hingewiesen, insbesondere, dass die Lesbarkeit wichtig ist.Ich würde nicht versuchen, das Programm mehr als das Folgende zu reduzieren.

use strict;
use warnings;
# http://stackoverflow.com/questions/5402405/
my $fnprot = shift || 'proteins.txt';
my $fndna  = shift || 'dna.txt';
# build protein table
open my $fhprot, '<', $fnprot or die "open $fnprot: $!";
my %proteins = split /\s+/, do { local $/; <$fhprot> };
close $fhprot;
# process dna data
my @result;
open my $fhdna, '<', $fndna or die "open $fndna: $!";
while (<$fhdna>) {
    tr/acgt/ACGT/;
    tr/GCTA/CGAU/;
    push @result, map $proteins{$_}, grep defined $proteins{$_}, m/(...)/g;
}
close $fhdna;
# check correctness of result (given input as per original post)
my $expected = 'SIMQNISGREAT';
my $got = join '', @result;
die "@result is not expected" if $got ne $expected;
print "@result - $got\n";

Das einzige "Einzeiler", das ich hinzugefügt habe, ist der push map grep m//g in der while-Schleife.Beachten Sie, dass Perl 5.10 den Operator "defined or" (//) hinzufügt, mit dem Sie Folgendes schreiben können:

push @result, map $proteins{$_} // (), m/(...)/g;

Ah, okay, die Slurp-Sprache für open do local $/-Dateien ist praktisch, um kleine Dateien in den Speicher zu schlürfen.Ich hoffe, Sie finden es ein bisschen inspirierend.:-)

Wenn Proteindaten in eine andere Datei geschrieben werden, wird der Speicherplatz begrenzt und ohne Zeilenumbruch.Sie können also Daten importieren, indem Sie die Datei einmal lesen.

#!/usr/bin/perl
use strict;
use warnings;      

open(INPUT, "<mydata.txt");
open(DATA, "<proteins.txt");
my %proteins = split(" ",<DATA>);

while (<INPUT>) {
    tr/GCTA/CGAU/;
    while(/(\w{3})/gi) {print $proteins{$1} if (exists($proteins{$1}))};
}
close(INPUT);
close(DATA);

Sie können die Codezeile " tr / a, c, g, t / A, C, G, T / " entfernen, da der Übereinstimmungsoperator die Option für den Fall hatunempfindlich ( i Option).Die ursprüngliche foreach -Schleife kann wie der obige Code optimiert werden.Die Variable $1 ist hier das Ergebnis des übereinstimmenden Musters in Klammern der Übereinstimmungsoperation /(\w{3})/gi

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top