列 1 に基づいて同じファイルの複数行をマージします。

列 1 に基づいて同じファイルの複数行をマージします。

私はまだプログラミングを学んでおり、多くのことを試しましたが、フォーマットを正しく指定できません。私タブ区切りファイルには17個の列と多数(約50,000個)の行があります。ファイルは最初の列に基づいてソートされます。同じ最初の列(A)を持つ行をマージしたいのですが、他の16列はすべて異なり、すべての情報を1行、好ましくは同じ列に保持したいと思います。セミコロン;それらの間の区切り文字として。出力ファイルでタブ文字を区切り文字として保持したいと思います。答えてくれてありがとう。私がどこで間違っているかを説明してください。 :)

私が今まで試したこと:

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,それを使用してフィールド区切り文字をコンマに設定します。
  • -lとを使用していますprint "foo\n"。各印刷呼び出しに改行文字が追加されたため、複数の空白行が-l生成されます。
  • 追加を使用しているので、$h{$F[0]}.", ".$F[1];最初に実行して定義されていない場合は、保存された値の先頭に追加の値を追加$h{$F[0]}します。,
  • 2番目のフィールドだけを見て、他のすべてのフィールドは無視します。

awk同様に、次の理由であなたの意志が失敗します。

  • 印刷中ですfoo""bar。これにより、各フィールド間にスペースを入れずに出力がリンクされます。タブで区切られた出力が欲しいprint foo,barですOFS="\t"
  • 2番目のフィールドだけを見て、他のすべてのフィールドは無視します。

答え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

関連情報