CSV 内の重複した列の値を見つける

CSV 内の重複した列の値を見つける

大きな csv ファイルから重複する ID を見つけようとしています。行ごとにレコードが 1 つだけありますが、重複を見つける条件は最初の列になります。<id>,<value>,<date>

例.csv

11111111,high,6/3/2019
22222222,high,6/3/2019
33333333,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

望ましい出力:

11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

出力に順序は必要ありません。

答え1

AWK の使用:

awk -F, 'data[$1] && !output[$1] { print data[$1]; output[$1] = 1 }; output[$1]; { data[$1] = $0 }'

これはすべての行を調べ、次のように動作します。

  • 最初の列の値がすでにわかっている場合は、それに一致する行を出力し、記憶した行を出力する必要があることに注意してください。
  • 最初の列が出力したい列と一致する場合は現在の行を出力します。
  • 最初の列にキーが付けられた現在の行を保存します。

答え2

sortすべての ID が同じ長さ (例では 8 文字) の場合、と GNU を使用してすべて実行できますuniq

$ sort file | uniq -Dw 8
11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

長さが同じでない場合でも、この方法を使用できますが、少し複雑になります。

$ tr ',' ' ' < file | sort  | rev | uniq -f2 -D | rev | tr ' ' ','
11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

答え3

awk -F, '$1 in m { print m[$1]$0; m[$1]=""; next } 
                 { m[$1]=$0 "\n" }' ex

答え4

これは、拡張された正規表現構造を利用することで実行できますGNU sed。まず、ファイルをパターン スペースにロードし、次にパターン スペースの先頭から繰り返しのない行を削除します。また、パターン\n\nスペースの最後にフラグ が配置され、そこで繰り返し行がスローされます。したがって、このフラグがパターン スペースの先頭までバブルアップすると => 操作は終了し、次に進んでパターン スペースからマーカーを削除し、stdout に出力できます。

$ sed -Ee '
   $!{
      N;s/^/\n/
      $s/$/\n\n/;D
   }
   /^([^,\n]*),[^\n]*\n(.*\n)?\1,/!D
   s/^([^\n]*)(.*)/\2\1\n/;/^\n\n/!D
   s/^\n\n//;s/\n$//
' inp

これは、POSIX-sedパターンまたはホールド スペースのいずれかで、どの時点でもファイル全体を維持しないという問題へのアプローチのバージョンであり、別の方法です。重複行が見つかるとすぐに、その行は stdout に出力され、参照行がマークされて出力されます。マークされるのは、次に重複が見つかったときに出力したくないためです。

$ sed -ne '
   H;g;y/\n_/_\n/
   /.*_\([^,_]*\)\(,[^_]*\)\[0]_\(.*_\)\{0,1\}\1,[^_]*$/{
      s//\1\2/;y/_\n/\n_/;p
      g;s/.*\n//p;g;y/\n_/_\n/
      s/\(.*_\([^,_]*\),[^_]*\)\[0]\(_\(.*_\)\{0,1\}\)\2,[^_]*$/\1[1]\3/
      s/_$//;y/_\n/\n_/;bh
   }
   /.*_\([^,_]*\)\(,[^_]*\)\[1]_\(.*_\)\{0,1\}\1,[^_]*$/{
      s/.*_//;y/_\n/\n_/;p
      g;s/\(.*\)\n.*/\1/;bh
   }
   y/_\n/\n_/;s/$/[0]/;:h;h
' inp

Perlこれは、配列のハッシュで行を維持するという問題に対する基本的なソリューションです。繰り返し行が見つかるとすぐに、配列を出力して空にし、重複した行も出力します。

$ perl -F, -lane '
   push(@{$h{$F[0]}},$_),next if ! exists $h{$F[0]};
   print for splice(@{$h{$F[0]}}),$_;
' inp

出力:

11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

関連情報