我是Perl的绝对新手以及一般的编程(不到一个月的经验)。
如果我要解决一个更大的问题,我会遇到一个需要解决的问题。
基本上,我有两个看起来像这样的数组:
@array1 = ('NM_1234' , '1452' , 'NM_345' , '5008' , 'NR_6145' , '256');
@array2 = ('NM_5673' , '2' , 'NM_345' , '5' , 'NR_6145' , '10');
@array1
包含ID编号,后跟长度。 id号是核苷酸序列,长度是序列的长度。
@array2
包含id编号,后跟每个G-Quadruplex结构的数量,因此一些序列仅包含2个此类结构,而其他序列包含10个或更多。
基本问题是,我需要为每个匹配的ID号添加@array2
@array1
中的“长度数字”(例如5008,256)。
例如,因为 NM_345 在两个数组中匹配,我需要添加 5008 ,以便最终结果变为 NM_345,5, 5008
与 NR_6145 和其他此类匹配类似(@array2
中有超过20,000个ID号)
到目前为止,我已经能够编写代码,只能在两个数组中搜索相同的id号。这是代码:
#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中的length元素添加到@ array2中?我需要使用splice命令,但是怎么做?
我想要的输出应该如下所示:
NM_345,5,5008 <br>
NM_6145,10,256<br>
etc
我还需要将此输出保存到一个文件中,稍后将对其进行分析,以查看长度与G-quadruplex数之间是否存在任何关联。
任何帮助或意见都将深表感谢。
感谢您抽出宝贵时间解决我的问题!
编辑:此编辑用于显示数据文件的外观。它们基本上是我写的其他程序的putput文件。
我的第一个名为Transcriptlength.fa的文件,其中有超过40,000个ID号进入@array1
,如下所示:
NR_037701
3353
NM_198399
2414
NR_026816
601
NR_027917
658
NR_002777
1278
我的第二个文件名为Quadcount.AllGtranscripts.fa,超过20,000个数字进入@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 :(得分: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)。
答案 1 :(得分: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__
部分允许我模拟从文件中读取,因为我不能在键盘上使用外部源)。
答案 2 :(得分:1)
您似乎无法读取数据文件以及生成所需的输出。除非您向我们展示文件数据的示例,否则我们无法解决问题的这一部分,但这是一个正确生成输出的解决方案。
最好将数据存储在哈希中,因为这样可以直接访问给定序列ID的长度和结构计数。幸运的是,您所描述的数组可以通过简单的赋值轻松转换为哈希值,因此这个简短的程序可以从您显示的数组中执行所需的操作。
循环中的grep /\D/, @array2
列表只选择@array2
中的所有序列ID,只选择那些包含非小数字符的元素。我已经这样做了,以防序列显示的顺序很重要。在您的最终程序中,您可能应该直接从文件处理数据,而不是将其读入数组,因此这不是问题。
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
<强>更新强>
您的文件数据非常适合设置段落模式,其中记录由数据文件中的空行分隔。要实现此目的,请将输入记录分隔符变量$/
设置为空字符串""
。
这个修订过的程序读取第一个文件中的记录,将它们分成空格(空格包括空格,制表符和换行符等),并构建一个散列%lengths
,将每个序列ID与其长度相关联。
第二个文件也是如此,这次检查序列ID是否出现在哈希中。如果是,则输出完整记录。
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";
}
遗憾的是,您选择的样本数据不包含匹配的序列ID,因此在针对该数据运行时,该程序没有输出。您的实际文件将更有效率。
答案 3 :(得分:0)
此
$data = join ('',@data); #Convert to string @data2 = split('\n',$data); #Explode along newlines
不会像您想象的那样创建阵列。它只是重新创建你开始的线条结构。我想你的意思是分开“,”逗号。使用调试工具。至少插入一个这样的打印块
print join(":", @data2);
查看数组中的实际内容。
在继续下一行之前让每一行都正常工作。然后,如果你无法弄清楚为什么一条线不起作用,你可以在这里发一个问题。
实际上,很难用它来表达你在代码中想说的内容,因为这些想法是不完整的。