0

我有下一个数据:

miRNA17 70      105     dvex699824      12      233
miRNA17 21      60      dvex699824      42      20
miRNA17 55      89      dvex699824      6       40
miRNA18 58      85      dvex701176      119     92
miRNA17 66      105     dvex703815      35      75
miRNA17 31      71      dvex703815      43      83
miRNA17 39      79      dvex703815      43      83
miRNA2  28      56      dvex731981      313     286
miRNA17 10      70      dvex735428      142     203
miRNA17 29      91      dvex735428      213     152
miRNA17 66      105     dvex735668      163     125

问题是:如果我有这6列,我需要按照这个规则进行分组和打印:

相同的 miRNA## \t 不管 \t 不管 \t 相同的 dvex#### \t 取较低的 \t 取最高的

例如,这是可能的输出:

miRNA17 21     105   dvex699824   6    233
miRNA18 58     85    dvex701176   119  92
miRNA17 31     105   dvex703815   35   83
miRNA2  28     56    dvex731981   313  286
miRNA17 10     105   dvex735428   142  203

通过哈希键作为数组解决此问题的可能方法是什么?

4

3 回答 3

2

顺序处理文件效率更高,而无需先将所有内容加载到大数组中,只要有可能。以下是这样的解决方案的样子:

my @output_line = split / /, <IN_FILE>;
while (<IN_FILE>)
{
    my @current_line = split / /, $_;

    if ($current_line[0] ne $output_line[0])
    {
         printf OUT_FILE "%-8s  %5d  %5d  %-10s  %3d %3d\n", @output_line;
         @output_line = @current_line;
    }
    else
    {
         $output_line[1] = $current_line[1] if ($current_line[1] < $output_line[1]);
         $output_line[2] = $current_line[2] if ($current_line[2] > $output_line[2]);
         $output_line[4] = $current_line[4] if ($current_line[4] < $output_line[4]);
         $output_line[5] = $current_line[5] if ($current_line[5] > $output_line[5]);
    }
}

printf OUT_FILE "%-8s  %5d  %5d  %-10s  %3d %3d\n", @output_line;

警告:您的问题表明输出行应该具有“相同的 dvex####”。但是,您的示例输出没有显示这一点。因此我忽略了这个要求。但是,您只需在if语句中添加另一个条件即可轻松引入该要求。

第二个警告:这种方法还需要将被分组为彼此相邻的行,就像它们在您的示例数据中一样。

于 2012-08-18T08:28:08.243 回答
1

这是一个简单的脚本,它将产生您想要的输出,尽管它比您的要求状态更多,因为它还检查第 2 列和第 3 列的最小/最大值。

我正在使用List::Util来获取最小/最大值,这纯粹是为了方便。该模块是自 v5.7.3 以来的核心,因此它不应该出现问题。使用Text::CSV是谨慎的做法,但可能不是必需的,具体取决于您的数据。假设您的列中没有非制表符空格,则可以使用 using split,这将删除模块依赖性。

use strict;
use warnings;
use Text::CSV;
use List::Util qw(min max);

my $csv = Text::CSV->new({
    sep_char => "\t",   
    eol => $/,      # required for $csv->print
    binary  => 1,});

my %data;
my @order;

# *DATA and *STDOUT represent file handles, and can be replaced with
# any other file handle as you require. DATA is used here for simplicity.
#
while (my $row = $csv->getline(*DATA)) {
    my ($mir, $dv) = @{$row}[0,3];

    my $field = "$mir/$dv";
    unless (defined $data{$field}) { # new fields are stored as-is
        push @order, $field;         # preserving original order of input
        $data{$field} = $row;
        next;
    }
    $data{$field}[1] = min($data{$field}[1], $row->[1]);
    $data{$field}[2] = max($data{$field}[2], $row->[2]);
    $data{$field}[4] = min($data{$field}[4], $row->[4]);
    $data{$field}[5] = max($data{$field}[5], $row->[5]);
}

for my $field (@order) {
    $csv->print(*STDOUT, $data{$field});
}


__DATA__
miRNA17 70  105 dvex699824  12  233
miRNA17 21  60  dvex699824  42  20
miRNA17 55  89  dvex699824  6   40
miRNA18 58  85  dvex701176  119 92
miRNA17 66  105 dvex703815  35  75
miRNA17 31  71  dvex703815  43  83
miRNA17 39  79  dvex703815  43  83
miRNA2  28  56  dvex731981  313 286
miRNA17 10  70  dvex735428  142 203
miRNA17 29  91  dvex735428  213 152
miRNA17 66  105 dvex735668  163 125

输出:

miRNA17 21      105     dvex699824      6       233
miRNA18 58      85      dvex701176      119     92
miRNA17 31      105     dvex703815      35      83
miRNA2  28      56      dvex731981      313     286
miRNA17 10      91      dvex735428      142     203
miRNA17 66      105     dvex735668      163     125

请注意,输出与您的不匹配,因为您未能区分样本输入最后一行的 dvex 数字。

于 2012-08-18T16:48:18.463 回答
1

Perl 脚本:

use strict;

# Not shown... Parse the data file, stuff into an array of arrays.

my @data = (
    [ 'miRNA17', 70, 105, 'dvex699824',  12, 233 ],
    [ 'miRNA17', 21,  60, 'dvex699824',  42,  20 ],
    [ 'miRNA17', 55,  89, 'dvex699824',   6,  40 ],
    [ 'miRNA18', 58,  85, 'dvex701176', 119,  92 ],
    [ 'miRNA17', 66, 105, 'dvex703815',  35,  75 ],
    [ 'miRNA17', 31,  71, 'dvex703815',  43,  83 ],
    [ 'miRNA17', 39,  79, 'dvex703815',  43,  83 ],
    [ 'miRNA2',  28,  56, 'dvex731981', 313, 286 ],
    [ 'miRNA17', 10,  70, 'dvex735428', 142, 203 ],
    [ 'miRNA17', 29,  91, 'dvex735428', 213, 152 ],
    [ 'miRNA17', 66, 105, 'dvex735668', 163, 125 ]
);

my %results;

foreach my $record (@data) {
    my ($mirna, $col2, $col3, $dvex, $col5, $col6) = @$record;
    $results{$mirna}{$dvex}{col2} = $col2; # don't care.
    $results{$mirna}{$dvex}{col3} = $col3; # don't care.
    $results{$mirna}{$dvex}{col5} = $col5
        if not $results{$mirna}{$dvex}{col5} or $results{$mirna}{$dvex}{col5} > $col5;
    $results{$mirna}{$dvex}{col6} = $col6
        if not $results{$mirna}{$dvex}{col6} or $results{$mirna}{$dvex}{col6} < $col6;      
}


foreach my $mirna (keys %results) {
    foreach my $dvex (sort keys %{$results{$mirna}}) {
        printf "%-8s  %5d  %5d  %-10s  %3d %3d\n",
            $mirna, $results{$mirna}{$dvex}{col2}, $results{$mirna}{$dvex}{col3},
            $dvex, $results{$mirna}{$dvex}{col5}, $results{$mirna}{$dvex}{col6};
    }
}

1;

输出:

miRNA2       28     56  dvex731981  313 286
miRNA17      55     89  dvex699824    6 233
miRNA17      39     79  dvex703815   35  83
miRNA17      29     91  dvex735428  142 203
miRNA17      66    105  dvex735668  163 125
miRNA18      58     85  dvex701176  119  92
于 2012-08-18T05:23:17.073 回答