折叠具有多个字段的行

时间:2014-03-10 17:58:00

标签: perl awk

我有这段代码:

awk '!seen[$1,$2]++{a[$1]=(a[$1] ? a[$1]", " : "\t") $2} END{for (i in a) print i a[i]} ' inputfile

我希望能够折叠包含两个以上字段的行,但总是以第一个字段作为索引。

输入文件(三列制表符分隔):

protein_1   membrane    1e-4
protein_1   intracellular   1e-5
protein_2   membrane    1e-50
protein_2   citosol 1e-40

所需的输出(三列制表符分隔):

protein_1   membrane, intracellular 1e-4, 1e-5
protein_2   membrane, citosol   1e-50, 1e-40

谢谢!

在这里堆叠:

awk '!seen[$1,$2]++{a[$1]=(a[$1] ? a[$1]"\t" : "\t") $2};{a[$1]=(a[$1] ? a[$1]", " : "\t") $3} END{for (i in a) print i a[i]} ' 1 inputfile

4 个答案:

答案 0 :(得分:3)

perl -lane'
  $ar = $h{shift @F} ||= [];
  push @{$ar->[$_]}, $F[$_] for 0,1;
  END {
    $" = ", ";
    print "$_\t@{$h{$_}[0]}\t@{$h{$_}[1]}" for sort keys %h;
  }
' file

输出

protein_1 membrane, intracellular 1e-4, 1e-5
protein_2 membrane, citosol 1e-50, 1e-40

答案 1 :(得分:3)

使用GNU awk进行二维数组:

$ gawk '
{ a[$1][$2] = $3 }
END {
    for (i in a) {
        printf "%s", i
        sep = "\t"
        for (j in a[i]) {
            printf "%s%s", sep, j
            sep = ", "
        }
        sep = "\t"
        for (j in a[i]) {
            printf "%s%s", sep, a[i][j]
            sep = ", "
        }
        print ""
    }
}' file
protein_1       membrane, intracellular 1e-4, 1e-5
protein_2       membrane, citosol       1e-50, 1e-40

答案 2 :(得分:2)

我真的希望有人发布一些awk魔法,但我会继续现在抛弃更长形式的perl脚本:

use strict;
use warnings;

my @cols = ();
my $lastprotein = '';

while (<DATA>) {
    chomp;
    my ($protein, @data) = split "\t";

    if ($protein ne $lastprotein && @cols) {
        print join("\t", $lastprotein, map {join ', ', @$_} @cols), "\n";
        @cols = ();
    }

    push @{$cols[$_]}, $data[$_] for (0..$#data);
    $lastprotein = $protein;
}

print join("\t", $lastprotein, map {join ', ', @$_} @cols), "\n";

__DATA__
protein_1   membrane    1e-4
protein_1   intracellular   1e-5
protein_2   membrane    1e-50
protein_2   citosol 1e-40

输出

protein_1       membrane, intracellular 1e-4, 1e-5
protein_2       membrane, citosol       1e-50, 1e-40

答案 3 :(得分:2)

这应该适合你:

awk '{
    col1[$1]++
    for(fld = 2; fld <= NF; fld++) {
        line[$1,fld] = (line[$1,fld]) ? line[$1,fld] ", " $fld : $fld
    }
}
END {
    for(name in col1) {
        printf "%s\t", name
        for(item = 2; item <= NF; item++) {
            printf "%s\t", line[name,item]
        }
        print ""
    }
}' file

<强>输出

protein_1       membrane, intracellular 1e-4, 1e-5
protein_2       membrane, citosol       1e-50, 1e-40