列 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 列があり、列 1 には多くの繰り返しがあるため、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すでに各 print 呼び出しに改行を追加しているため、複数の空白行が存在することになります。
  • 追加するために使用している$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

関連情報