列出列表中的唯一位置以及相关的字符串

时间:2014-11-04 11:12:41

标签: regex perl

我需要列出文件中的唯一数字位置,然后在每个位置后枚举唯一的indel。

如果有多个不同的indel,那么我希望每个position / indel都列在不同的行上。

我认为List::MoreUtils:uniq是最好的解决方案,但我没有运气。是否有无模块方法?

如果我的解释没有意义,请告诉我。

FILE1数据:

7065_8#10 99269 -t
7065_8#10 126477 -c
7065_8#10 413711 +T
7065_8#10 586681 -a
7065_8#10 820739 +T
7065_8#10 927102 +T
7065_8#10 942973 +T
7065_8#10 1075448 +G
7065_8#11 99269 -t
7065_8#11 126477 -t
7065_8#11 413711 +T
7065_8#11 470211 +G
7065_8#10 927102 -a
7065_8#10 942973 +T 

中级结果:

99269 ( -t -t )
126477 ( -c -t )
413711 ( +T +T )
586681 ( -a )
820739 ( +T )
927102 ( +T -a )
942973 ( +T +T )
1075448 ( +G )
470211 ( +G )

最终输出:

99269 ( -t )
126477 ( -c )
126477 ( -t )
413711 ( +T )
586681 ( -a )
820739 ( +T )
927102 ( +T )
927102 ( -a )
942973 ( +T )
1075448 ( +G )
470211 ( +G )

这是我的初始(不成功)代码:

#!/usr/bin/perl 

use strict;
use warnings;
use autodie;
use 5.010;

my $outputfile = "/Users/edwardtickle/Documents/positionarray.txt"; 

open FILE1, "/Users/edwardtickle/Documents/CC22indelscc.txt";

open (OUTPUTFILE, ">$outputfile");

use List::MoreUtils qw(uniq);
my @bases = ();
my @words = ();

while (<FILE1>) {
  if (/^\S+\s+(\d+)\s+(\S+)/) {
    push @words, $1;
  }
}

my @unique_words = uniq @words;

print OUTPUTFILE "@unique_words\n";

close FILE1;
close OUTPUTFILE;

目前这给我一个由空格分隔的一行上的唯一位置列表,我不知道如何每行打印一个。

4 个答案:

答案 0 :(得分:2)

好的,我会列出错误列表,而不是将它们作为评论发布,因为它们开始加载。

  • \@unique_words "@bases";是语法错误。你需要在它们之间加一个逗号。
  • my @words = (); my @uniq_words = uniq @words;除了空列表外无法生成任何内容。使用my时,在该范围(块)中创建一个新变量。
  • 在循环中使用my @words = qw($1);。这是错误的,因为:
    1. 每次循环迭代创建一个新变量
    2. 每次使用=代替push,
    3. 覆盖该数组
    4. qw($1)不会插入变量,因此它只返回文字$1。你根本不需要qw(),而应该把价值推到另一条线上。

这是你做的事情:

  • 不是使用正则表达式来匹配,而是分割线,例如my ($junk, $num, $indel) = split
  • 只需使用shell重定向和菱形运算符<>,而不是显式打开输入和输出文件。 while (<>)perl script.pl input.txt > output.txt
  • 将分组的相关结果存储在哈希中,例如$data{$num}{$indel}++。如果您需要保留订单,请将唯一编号存储在数组中。
  • 在循环之后,浏览存储的唯一数字并使用类似print "$num ( " . join(" ", keys %{$data{$num}}) . ")\n";
  • 之类的内容打印哈希中的关联键

修改

阅读评论后,很明显订单无关紧要,并且&#34; indels&#34;应该分开排列。这使我们可以简单地打印文件中显示的值(保留原始顺序),并保留同时打印的副本。

use strict;
use warnings;

my %data;
while (<>) {
    my ($junk, $num, $indel) = split;
    unless (exists $data{$num}{$indel}) {
        print "$num ( $indel )\n";
    }
    $data{$num}{$indel}++;
}

<强>用法:

perl program.pl input.txt > output.txt

事实上,作为纯粹的学术练习,这可以进一步减少。通过(ab)使用postfix incrementmentation ++第一次在未初始化的值上使用时返回false值的事实,我们可以结合检查和增量:

my %data;
while (<DATA>) {
    my ($junk, $num, $indel) = split;
    unless ($data{$num}{$indel}++) {   # both check and incrementation
        print "$num ( $indel )\n";
    }
}

请注意,这只是为了好玩,不建议用于生产代码,因为它相当模糊。

答案 1 :(得分:2)

我认为这个程序按照你的要求行事,但你的问题并不清楚。它构建了哈希散列,无需单独的uniq调用。

我不清楚数字位置 indels 是什么,特别是因为你的Perl代码中没有出现任何术语,但我已经做了最好的猜测。< / p>

我能说的是位置/插入对的顺序是否在一个位置有多个indel的情况下很重要。此代码按照它们在哈希中出现的顺序打印它们,这实际上是随机的。如果您需要不同的顺序,例如按字母顺序排列,或者与文件中出现的顺序相同,那么您必须这样说。

我相信您很乐意改变此解决方案,使其能够读取和写入外部文件,而不是使用DATASTDOUT

use strict;
use warnings;

my %data;

while (<DATA>) {
  my ($base, $word) = (split)[1,2];
  ++$data{$base}{$word}
}

for my $base (sort { $a <=> $b } keys %data) {
  for my $word (keys %{ $data{$base} }) {
    print "$base ( $word )\n";
  }
}

__DATA__
7065_8#10 99269 -t
7065_8#10 126477 -c
7065_8#10 413711 +T
7065_8#10 586681 -a
7065_8#10 820739 +T
7065_8#10 927102 +T
7065_8#10 942973 +T
7065_8#10 1075448 +G
7065_8#11 99269 -t
7065_8#11 126477 -t
7065_8#11 413711 +T
7065_8#11 470211 +G
7065_8#10 927102 -a
7065_8#10 942973 +T 

<强>输出

99269 ( -t )
126477 ( -t )
126477 ( -c )
413711 ( +T )
470211 ( +G )
586681 ( -a )
820739 ( +T )
927102 ( +T )
927102 ( -a )
942973 ( +T )
1075448 ( +G )

答案 2 :(得分:0)

使用一个哈希,它给你的唯一性默认是这样的:

my %indel_lookup = ();
while (<FILE1>) {
     if (/^\S+\s+(\d+)\s+(\S+)/) {
         $indel_lookup{$1}{$2} = undef;
     }
}

打印出来使用两个foreach循环

foreach my $position (keys %indel_lookup) {
   foreach my $indel (keys %{$indel_lookup{$position}}) {
        print "$position ( $indel )\n";
   }
}

除了拼写错误(因为它未经测试),它应该可以正常工作。

答案 3 :(得分:-1)

我删除了use strict全局变量。如果您需要use strict,只需在全局变量前添加my即可。这是解决方案:

#!/usr/bin/perl

#use strict;
use warnings;
use autodie;
use 5.010;

my $outputfile = "out.txt";

open FILE1, "in.txt";

open (OUTPUTFILE, ">$outputfile");

use List::MoreUtils qw(uniq);

%words = ();
while (<FILE1>) {
    if (/^\S+\s+(\d+)\s+(\S+)/) {
       $words{$1} .= " ".$2;
    }
}
close FILE1;

for $key (keys(%words)) {
     open FF, ">tmp.txt";
     @uniq_words = uniq split (/\s+/,$words{$key});   
    for $w (@uniq_words) {
        if ($w !~ /^\s*$/) {
            print OUTPUTFILE "$key ( $w )\n";
        }
    }
}

close OUTPUTFILE;