2016-08-12 5 views
0

У меня есть файл с разделителями в виде вкладок с повторяющимися значениями в первом столбце. Единичные, но повторяющиеся значения в первом столбце соответствуют нескольким значениям во втором столбце. Это выглядит примерно так:Анализ файла на основе идентификатора столбца: perl

AAAAAAAAAA1  m081216|101|123 
    AAAAAAAAAA1  m081216|100|1987 
    AAAAAAAAAA1  m081216|927|463729 
    BBBBBBBBBB2  m081216|254|260489 
    BBBBBBBBBB2  m081216|475|1234 
    BBBBBBBBBB2  m081216|987|240 
    CCCCCCCCCC3  m081216|433|1000 
    CCCCCCCCCC3  m081216|902|366 
    CCCCCCCCCC3  m081216|724|193 

Для каждого типа последовательности в первом столбце, я пытаюсь напечатать в файл только с последовательностями, которые соответствуют ей. Имя файла должно включать повторяющуюся последовательность в первом столбце и количество последовательностей, которые соответствуют ему во втором столбце. В приведенном выше примере я бы поэтому имел 3 файла по 3 последовательностей. Первый файл будет называться что-то вроде «AAAAAAAAAA1.3.txt» и выглядеть следующим образом при открытии:

m081216|101|123 
    m081216|100|1987 
    m081216|927|463729 

Я видел другие подобные вопросы, но они ответили, используя хэш. Я не думаю, что не могу использовать хеш, потому что мне нужно поддерживать количество связей между столбцами. Может быть, есть способ использовать хэш хешей? Я не уверен. Вот мой код.

use warnings; 
    use strict; 
    use List::MoreUtils 'true'; 

    open(IN, "<", "/path/to/in_file") or die $!; 

    my @array; 
    my $queryID; 

    while(<IN>){ 
      chomp; 
      my $OutputLine = $_; 
      processOutputLine($OutputLine); 
    } 


    sub processOutputLine { 
      my ($OutputLine) = @_; 
      my @Columns = split("\t", $OutputLine); 
      my ($queryID, $target) = @Columns; 
      push(@array, $target, "\n") unless grep{$queryID eq $_} @array; 
      my $delineator = "\n"; 
      my $count = true { /$delineator/g } @array; 
      open(OUT, ">", "/path/to/out_$..$queryID.$count.txt") or die $!; 
      foreach(@array){ 
        print OUT @array; 
      } 
    } 
+0

Вы, вероятно, также необходимо удалить файл записи из цикла, или вы будете писать над ним с каждой строкой данных. –

ответ

3

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

use warnings; 
use strict; 
use feature qw(say); 

my $filename = 'rep_seqs.txt'; # input file name 
open my $in_fh, '<', $filename or die "Can't open $filename: $!"; 

my %seqs; 
foreach my $line (<$in_fh>) { 
    chomp $line; 
    my ($id, $seq) = split /\t/, $line; 
    push @{$seqs{$id}}, $seq; 
} 
close $in_fh; 

my $out_fh; 
for (sort keys %seqs) { 
    my $outfile = $_ . '_' . scalar @{$seqs{$_}} . '.txt'; 
    open $out_fh, '>', $outfile or do { 
     warn "Can't open $outfile: $!"; 
     next; 
    }; 
    say $out_fh $_ for @{$seqs{$_}}; 
} 
close $out_fh; 

С вашим входом я получаю нужные файлы, названные AA..._count.txt, с соответствующими им три линий каждой. Если элементы, разделенные |, должны быть разделены, вы можете это сделать, например, при написании.

Комментарии

  • анонимный массив для ключа $seqs{$id} создается, когда мы push, если не существует уже

  • Если есть проблемы с закладками (преобразуются в пробелы?), Используйте ' '. См. Комментарий.

  • дескриптор закрыт и вновь открыт на каждом open, поэтому нет необходимости закрывать каждый раз, когда


Шаблон по умолчанию для split является ' ', также вызывая специфическое поведение - это соответствует «любые смежные пробелы», а также опускает пробелы. (Образец / / соответствует одному пространству, отключив это специальное поведение: ' '.) См. Более точное описание на странице split. Таким образом, целесообразно использовать ' ' при расщеплении на неопределенное количество пробелов, поскольку в случае split это немного идиоматично, возможно, является наиболее распространенным использованием и является его значением по умолчанию. Спасибо Borodin за отзыв этого комментария и обновления (у исходного сообщения был эквивалент /\s+/).

Обратите внимание, что в этом случае, так как ' ' по умолчанию вместе с $_, мы можем сократить его немного

for (<$in_fh>) { 
    chomp; 
    my ($id, $seq) = split; 
    push @{$seqs{$id}}, $seq; 
} 
+0

Спасибо за вашу помощь и проницательные комментарии. Я заметил, что в вашем ответе «close $ fh_in;» должен быть действительно «close $ in_fh;». Кроме того, что касается второй половины моего вопроса, есть ли у вас какие-либо уловки о том, как добавить имя каждого файла с количеством последовательностей, содержащихся в этом конкретном файле? Еще раз спасибо за вашу огромную помощь !!! – Rob

+0

@Rob Спасибо за эти комментарии! Мне нравится отмечать дескрипторы файлов как '$ specs_fh' - будет исправлено. И я забыл о вашем требовании добавить счетчик для имени, добавит это сейчас. Спасибо за атрибуцию. – zdim

+0

@Rob Я добавил счет к имени файла. 'Scalar' возвращает длину списка (количество элементов), а ссылки массива могут использоваться как списки с помощью разыменования' @ {array_ref} ', поэтому это очень просто. Я разделяю счет в имени файла на '_', если вы действительно хотите' .', пожалуйста, измените '' _'' на '' .''. – zdim

Смежные вопросы