
Ich habe mehrere durch Tabulatoren getrennte Fastq-Dateien. Ich möchte die zweite Zeile jedes Lesevorgangs abgleichen und die daneben liegenden Werte addieren, wenn sie übereinstimmen. Beispiel:
file1.fq
>1
ATGCCGTT file1:1
+
HHHHKKKK
file2.fq
>2
ATGCCGTT file2:3
+
JJKHHTTT
>3
ATTCCAAC file2:1
+
=#GJLMNB
Die gewünschte Ausgabe sieht etwa so aus:
output.txt
ATGCCGTT file1:1 file2:3 count:4
ATTCCAAC file2:1 count:1
Der Code, den ich geschrieben habe, ist:
#!/usr/bin/env perl
use strict;
use warnings;
no warnings qw( numeric );
my %seen;
$/ = "";
while () {
chomp;
my ($key, $value) = split ('\t', $_);
my @lines = split /\n/, $key;
my $key1 = $lines[1];
$seen{$key1} //= [ $key ];
push (@{$seen{$key1}}, $value);
}
foreach my $key1 ( sort keys %seen ) {
my $tot = 0;
my $file_count = @ARGV;
for my $val ( @{$seen{$key1}} ) {
$tot += ( split /:/, $val )[0];
}
if ( @{ $seen{$key1} } >= $file_count) {
print join( "\t", @{$seen{$key1}});
print "\tcount:". $tot."\n\n";
}
}
Dieser Code funktioniert gut für kleine Dateien, aber wenn ich große Dateien vergleichen möchte, belegt er den gesamten Speicher, sodass das Skript ohne Ergebnisse ausgeführt wird. Ich möchte das Skript so ändern, dass es keinen Speicher belegt. Ich möchte keine Module verwenden. Ich denke, wenn ich jeweils nur eine Datei in den Speicher lade, wird zwar Speicher gespart, aber ich kann es nicht. Bitte helfen Sie mir, mein Skript zu ändern.
Antwort1
Haben Sie es versucht awk
? Ich bin nicht sicher, ob es mit großen Dateien besser zurechtkommt als, perl
aber einen Versuch könnte es wert sein:
In Ihrem Awk-Skript:
BEGIN {
RS=">[0-9]+"
}
FNR==1{next}
NR==FNR {
a[$1]++
next
}
$1 in a {
b[$1]++
next
}
{
c[$1]++
}
END {
for (key in a) {
if (b[key] == "") {
printf key"\tfile1:"a[key]"\t\tcount:"a[key]"\n"
} else {
printf key"\tfile1:"a[key]"\tfile2:"b[key]"\tcount:"a[key]+b[key]"\n"
}
}
for (key in c) {
printf key"\t\tfile2:"c[key]"\tcount:"c[key]"\n"
}
}
So führen Sie es aus:
$ awk -f myscript.awk file1 file2 > output.txt
Getestet mit:
Datei1
>1
ATGCCGTT file1:1
+
HHHHKKKK
>2
ATTCCAACg file2:1
+
=#GJLMNB
Datei2
>2
ATGCCGTT file2:3
+
JJKHHTTT
>3
ATTCCAAC file2:1
+
=#GJLMNB
Ausgabe im Terminal:
ATTCCAACg file1:1 count:1
ATGCCGTT file1:1 file2:1 count:2
ATTCCAAC file2:1 count:1
Antwort2
Fügen Sie diese mystischen Beschwörungen zu Ihrem Programm hinzu
use DB_File;
my %seen;
unlink '/tmp/translation.db';
sleep 2;
tie ( %seen, 'DB_File', '/tmp/translation.db' )
or die "Can't open /tmp/translation.db\n";
und Ihr Hash wird nicht mehr im Speicher, sondern in einer Datenbank auf der Festplatte gespeichert. Sie können den Rest Ihres Codes genau so lassen, wie er ist. Ich habe zwar das Modul DB_File verwendet, aber es gibt wirklich keinen Grund, das nicht zu tun. Es ist in jedemperlDie Installation ist sofort einsatzbereit, Sie müssen es also nicht installieren oder ähnliches.
Ich verwende diesen Ansatz ständig, wenn meine Hashes wirklich riesig werden, und ich stelle fest, dass sich die Dinge nach dem Überschreiten eines vage definierten Größenpunkts erheblich beschleunigen.