2012-06-20 3 views
2

Я абсолютный новичок в Perl, а также программирование в целом (менее месяца).«Perl: добавьте элемент массива из одного массива в другой массив»

Я столкнулся с проблемой, которая должна быть решена, если я хочу решить большую проблему.

В принципе, у меня есть 2 массивы, которые выглядят следующим образом:

@array1 = ('NM_1234' , '1452' , 'NM_345' , '5008' , 'NR_6145' , '256'); 
@array2 = ('NM_5673' , '2' , 'NM_345' , '5' , 'NR_6145' , '10'); 

@array1 содержит идентификационные номера следуют длины. Идентификатор содержит нуклеотидные последовательности, а длина - длина последовательности.

@array2 содержит номера идентификаторов, за которыми следует число структур G-Quadruplex, поэтому некоторые последовательности содержат только 2 таких структуры, в то время как другие содержат 10 или более.

Основная проблема заключается в том, что я должен добавить к @array2 «номера длины» в @array1 (например, 5008, 256) для каждого совпадающего идентификационного номера.

Так, например, как NM_345 матчей в обоих массивах, мне нужно добавить к нему, так что конечный результат становится как NM_345,5,5008.

Аналогично с NR_6145 и других подобных матчей (Есть более 20000 идентификационные номера в @array2)

До сих пор я был в состоянии написать код, который может просто искать тот же номер документа в обоих массивах , Вот код:

#Enter file name 
print "Enter file name: "; 
$in =<>; 
chomp $in; 

open(FASTA,"$in") or die; 

@data = <FASTA>; #Read in data   
$data = join ('',@data); #Convert to string 
@data2 = split('\n',$data); #Explode along newlines 

#Enter 2nd file name 
print "\n\nEnter 2nd file name: "; 
$in2=<>; 
chomp $in2; 

open(FASTA,"$in2") or die; 
@entry =<FASTA>; #Read in data 

$entry = join('',@entry); #Convert to string 
@entry2 = split('\n',$entry); #Explode along newlines 

my %seen; 
for $item (@data2) { 
    if($item =~ /([0-9]+)/){ 
     push @{$seen{$key}}, $item;#WHAT IS THIS DOING? HOW? 
    } 
} 

for my $item (@entry2) { 
    if ($item =~ /([0-9]+)/){ 
     if (exists $seen{$key}) { 
      print $item,"\n"; 
     };   
    } 
} 
exit; 

Я полученный код, который находит один и тот же элемент из 2 массивов из этого решения здесь, так что полная заслуга Chas.Owens: https://stackoverflow.com/a/1064929/1468737. И, конечно, я не совсем понимаю, пока эта часть:

push @{$seen{$key}}, $item;#WHAT IS THIS DOING? HOW? 

Это, как представляется, массив хэш-значение или что-то?

Итак, как теперь добавить элемент длины из @ array1 в @ array2? Мне нужно использовать команду сращивания, я думаю, но как?

Моего желаемый результат должен выглядеть следующим образом:

NM_345,5,5008 <br> 
NM_6145,10,256<br> 
etc 

Мне также нужно сохранить этот вывод в файл, который потом будет проанализирован, чтобы увидеть, есть ли корреляция между длиной и числом G-квадруплексным.

Любая помощь или ввод будет оценен по достоинству.

Благодарим вас за то, что нашли время, чтобы пройти через мою проблему!


EDIT: Это изменение должно показать, как выглядят файлы данных. Они в основном являются файлами putput из других программ, которые я написал.

Мой первый файл, названный, Transcriptlength.фа, с более чем 40 000 идентификационные номера вдаваясь в @array1 выглядит следующим образом:

NR_037701 
3353 

NM_198399 
2414 

NR_026816 
601 

NR_027917 
658 

NR_002777 
1278 

Мой второй файл, названный Quadcount.AllGtranscripts.fa, с более чем 20,000id номера вдаваясь в @array2, выглядит следующим образом:

NM_000014 
1 

NM_000016 
3 

NM_000017 
19 

NM_000018 
2 

NM_000019 
3 

NM_000020 
30 

NM_000021 
1 

NM_000022 
2 

NM_000023 
5 

NM_000024 
1 

NM_000025 
15 

NM_000029 
5 
+0

Каков формат данных в каждом файле? – beresfordt

+1

Есть ли причина, по которой вы не можете объявить эти массивы вверху, как хэши? Это сделало бы решение Im набирать намного легче. – PinkElephantsOnParade

+0

Первый массив не может быть легко преобразован в хеш, я полагаю. По крайней мере, я построил свое решение, предполагая именно это: можно хранить несколько длин для каждой последовательности.) – raina77ow

ответ

1

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

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

Список grep /\D/, @array2 в цикле просто выбирает все идентификаторы последовательности от @array2, выбирая только те элементы, которые содержат не десятичный символ. Я сделал это таким образом, если порядок, в котором отображаются последовательности, имеет значение. В вашей последней программе вы, вероятно, должны обрабатывать данные непосредственно из файла, а не читать их в массив, чтобы это не было проблемой.

use strict; 
use warnings; 

my @array1 = (NM_1234 1452 NM_345 5008 NR_6145 256); 
my @array2 = (NM_5673 2 NM_345 5 NR_6145 10); 

my %lengths = @array1; 
my %counts = @array2; 

for my $id (grep /\D/, @array2) { 
    my $length = $lengths{$id}; 
    printf "%s,%s,%s\n", $id, $length, $counts{$id} if $length; 
} 

выход

NM_345,5008,5 
NR_6145,256,10 

Update

Ваш файл данных идеально подходит для установки режима пункт где записи разделены пустыми строками в файле данных. Для этого вы устанавливаете разделитель входных записей переменной $/ на пустую строку "".

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

То же самое делается со вторым файлом, на этот раз проверяющим, появляется ли идентификатор последовательности в хеше. Если это так, выводится полная запись.

use strict; 
use warnings; 

my $fh; 
my %lengths; 

$/ = ""; 

open $fh, '<', 'Transcriptlength.fa' 
    or die qq(Unable to open "Transcriptlength.fa": $!); 

while (<$fh>) { 

    my ($id, $length) = split; 
    next unless $id; 

    $lengths{$id} = $length; 
} 

open $fh, '<', 'Quadcount.AllGtranscripts.fa' 
    or die qq(Unable to open "Quadcount.AllGtranscripts.fa": $!); 

while (<$fh>) { 

    my ($id, $count) = split; 
    next unless $id; 

    my $length = $lengths{$id}; 
    next unless $length; 

    print join(',', $id, $count, $length), "\n"; 
} 

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

+0

Wow Borodin! Спасибо за прекрасный ответ и такой восхитительный код! Действительно, вы правы, мне трудно читать файлы данных. Я отредактировал исходный пост, и теперь я рассказал о том, как выглядят два файла данных. – Neal

+0

Код, который вы упомянули, прекрасно работает, если мои данные могут быть приведены в эту конкретную форму в массиве. К сожалению, это, похоже, не так :(Как мне получить данные из 2-х файлов в хэш-форму? – Neal

+0

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

1

Слишком много вопросов для одного вопроса ... Но здесь мы идем в любом случае:

push @{$seen{$key}}, $item; 

%seen хэш (или ассоциативный массив), так $seen{$key} восстанавливает от %seen значение, связанное с этим ключом $key. Затем это значение рассматривается как ссылка на массив и преобразуется в массив с помощью оператора @{}. Наконец, в конце этого массива добавляется $item.

Я не понимаю, что вы подразумеваете под длиной ... Вы имеете в виду предыдущую длину массива?

И чтобы сохранить это в файле, вам просто нужно print() в сценарии и перенаправление в файл при выполнении сценария, например:

./my_perl_script.pl > my_output_file 

То же самое для ввода имени файла, вы не действительно нужно open(), close() и тому подобное. Это более гибкий и быстрее код:

./my_perl_script.pl < my_input_file 

Это позволяет трубе этого в более простой способ и передавать данные из/в другие скрипты/процессы. Конечно, оба переназначения могут быть использованы одновременно:

./my_perl_script.pl <my_input_file> my_output_file 

Кроме того, вы даже не нужно сохранять в файл (а это всегда полезно иметь копию обработанных данных в любом случае), и вы можете трубы напрямую результаты в другом процессе, как

./my_perl_script.pl | my_other_script 

Это работает на всех ОС, которые я использовал в далекую (Windows, Linux, OS X, BSD).

+0

Wow m0skit0! Большое спасибо за то, что нашли время, чтобы пройти мою проблему и терпеливо написать мне ответ. Это объяснение push @ {{$ seen {$ key}} было потрясающим! Большое спасибо! Это полностью новая * структура данных для меня, по крайней мере, она не рассматривается в книге, я имею в виду: Начало Perl для биоинформатики. Я мог бы понять часть {$ seen {$ key}, но рассматривая ее как аргумент массива и преобразовывая его в массив, ничего себе! Это было совершенно новое! – Neal

+0

Под «длиной» Я имею в виду значение длины, связанное с каждым id, например, значение длины id 'NM_345' равно '5008' в @ array1 – Neal

+0

Эти отличные строки для сохранения результата настолько изящны! Конечно, выходной файл также сохраняет подсказки пользователя «Введите имя файла» и «Введите второе имя файла». Ожидается ли это? Команда входного файла работает как сон! – Neal

1

ОБНОВЛЕНИЕ: Я оставляю the link к исходному коду ответа, чтобы проиллюстрировать концепцию абстрагирования различных подзадач (особенно обработки). Но ваша проблема может быть решена намного проще, если вы уверены, что ожидать во входных файлах:

use warnings; 
use strict; 

my $lengths_filename = 'Transcriptlength.fa'; 
my $counts_filename = 'Quadcount.AllGtranscripts.fa'; 

my %sequence; # it will be the basic data repository 

local $/ = ''; 
# ...by this we ensure that files will be read by logical blocks instead of lines. 
# Might need some tweaking, if 'empty line' in your sample is not really empty. 

# we start processing from 'counts' file, as only those records present in it 
# should actually be in our output: 
open my $cfh, '<', $counts_filename 
    or die $!, "\n"; 
while (<$cfh>) { 
    # each logical block consists of two parts, divided by whitespace 
    my ($name, $count) = split; 

    # here goes magic: we simultaneously create a new record in our repository... 
    # ... and set its 'count' property to the value, extracted from the scanned fileblock 
    $sequence{$name}{count} = $count; 
} 
close $cfh; 

# now we go for lengths, approach is almost the same 
open my $lfh, '<', $lengths_filename or die $!, "\n"; 
while (<$lfh>) { 
    my ($name, $length) = split; 

    # here we check that the sequence was in 'counts' file 
    if (exists $sequence{$name}) { 
    $sequence{$name}{length} = $length; 
    } 
} 
close $lfh; 

# and now the output block: it's mostly the same as in the original answer: 
for my $name (sort keys %sequence) { 
    print "$name, $sequence{$name}{count}, $sequence{$name}{length}", "\n"; 
} 

Вот еще codepad, чтобы показать, как это работает. Не возражайте странно __DATA__, это просто для этой конкретной версии программы (используя раздел __DATA__, позволяет мне симулировать чтение из файлов, так как я не могу использовать внешние источники в кодексе).

+1

Вы сделали домашнее задание для него, это значит, что вы получаете оценку вместо этого? – starbolin

+2

Ну, я часто помогаю людям «генетики» с подробным объяснением и связкой строк кода, чтобы проиллюстрировать это. Я не думаю, что это домашнее задание, я думаю об этом, поскольку задача должна быть решена человеком, который не знает достаточно, чтобы это сделать, но это желание учиться. Вот почему я даю ему не только некоторые основные принципы или ссылки на документацию, но и настоящую пищу для размышлений. – raina77ow

+0

Твой был хорошо написан и не заслужил моего замечания. Трудно сказать, сколько нужно отдавать, и я больше старому программисту, чем тип учителя-пациента ;-) – starbolin

0

Этот

 $data = join ('',@data); #Convert to string 
@data2 = split('\n',$data); #Explode along newlines

Не создать массив, как вы думаете. Он просто воссоздает структуру строчки, с которой вы начали. Я думаю, вы хотели разделиться на "," запятые. Используйте инструменты отладки. Минимально вставьте блок печати, подобный этому

print join(":", @data2);

, чтобы увидеть, что на самом деле находится в вашем массиве.

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

Как бы то ни было, трудно сказать, что вы пытались сказать в коде, потому что идеи неполны.

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