根据第 1 列合并同一文件中的多行

根据第 1 列合并同一文件中的多行

我仍在学习编程,并且尝试了很多方法,但无法获得正确的格式。我有一个制表符分隔文件有 17 列和许多(大约 50.000)行。该文件已按第一列排序。我想合并具有相同第一列 (A) 的行,但所有其他 16 列都不同,并且我想将所有信息保留在一行中,最好在同一列中分号 ;作为它们之间的分隔符。我想在输出文件中保留制表符作为分隔符。非常感谢您的回答,如果您也能解释我出错的地方,那就更好了:)。

到目前为止我已经尝试过:

awk -F'\t' 'NF>1{a[$1] = a[$1]";"$2}END{for(i in a){print i""a[i]}}' filename.txt

perl -F',' -anle 'next if /^$/;$h{$F[0]} = $h{$F[0]}.", ".$F[1];
END{print $_,$h{$_},"\n" for sort keys %h}' filename.txt

文件格式(其他 15 列与 B 列格式相同)

A     B     C    
123   fvv   ggg
123   kjf   ggg
123   ccd   att
567   abc   gst
567   abc   hgt
879   ttt   tyt

我想要的输出(我需要所有 17 列,对于第 2-16 列,我需要与 B 列和 C 列相同的输出)。 B 的所有情况都应在 B 下,C 的所有情况应在 C 下,D 的所有情况应在 D 下,等等。因此,输出与输入一样有 17 列,而不是 50.000 行,现在应该有大约 20.000 行,因为第一列有很多重复(对于这个特定文件):

A     B                C
123   fvv;kjf;ccd      ggg;ggg;att
567   abc;abc          gst;hgt
879   ttt              lll

答案1

awk '{
      if(NR!=1){a[$1]=$2";"a[$1]}
      else print $0}
    END{
      n = asorti(a, b);
      for (n in b) {
      print b[n],a[b[n]]
      }
    }'

答案2

Perl 解决方案:

$ perl -F"\t" -anle 'if($.==1){print; next} push @{$k{$F[0]}},@F[1..$#F]; 
  END{print "$_\t" . join(";",@{$k{$_}}) for sort keys(%k)}' file 
A   B   
123 fvv;kjf;ccd
567 abc;abc
879 ttt

这可以适用于任意数量的字段。但是,它确实需要将相当多的内容加载到内存中,如果您的文件很大,这可能会成为问题。


至于你哪里出错了,我们无法告诉你,除非你解释实际发生了什么,但是,在我的脑海中,你的 perl 尝试会失败,因为:

  • 当您的输入有制表符时,您正在使用-F,它将字段分隔符设置为逗号。
  • 您正在使用-lprint "foo\n"。已经-l为每个打印调用添加了一个换行符,因此您将有多个空白行。
  • 您正在使用$h{$F[0]}.", ".$F[1];附加,因此第一次运行且未$h{$F[0]}定义时,您将,在存储值的开头添加一个额外的值。
  • 您只查看第二个字段,忽略所有其他字段。

同样,你的意志awk也会失败,因为:

  • 您正在打印foo""bar,这将连接输出,每个字段之间没有空格。您想要print foo,bar并且也想要OFS="\t"制表符分隔的输出。
  • 您只查看第二个字段,忽略所有其他字段。

答案3

为这一句抱歉,但事情是这样的——

awk 'BEGIN{FS="\t"} {for(i=2; i<=NF; i++) { if (!a[$1]) a[$1]=$1FS$i ;else a[$1]=a[$1]";"$i};if ($1 != old) b[j++] = a[old];old=$1 } END{for (i=0; i<j; i++) print b[i] }' 1

123 fvv ;kjf;ccd
567 abc;abc
879 ttt

答案4

awk '
    function p(n,A){
        s = n
        for(i=2;i<=NF;i++){
            s = s "\t" A[i]
            A[i] = $i
        }
        if(n)
            print s
    }
    NR==1{
        print
        next
    }
    $1==n{
        for(i=2;i<=NR;i++)
            A[i] = A[i] ";" $i
        next
    }
    {
        p(n,A)
        n = $1
    }
    END{
        p(n,A)
    }
    ' file

相关内容