csvファイルをルックアップ列1と比較し、列2の値を確認します。

csvファイルをルックアップ列1と比較し、列2の値を確認します。

さて、私が何をすべきかを説明しようとします。デフォルトでは、次の例に示すように2つのCSVファイルがあります。

ファイル1:

Column 1, Column 2
abc     , 123
def     , 234
adf     , 567

ファイル2

Column 1, Column 2
abc     , 123
def     , 234
adf     , 578

次の手順を実行するには、シェルスクリプトまたは単純なコマンドを作成する必要があります。

  1. 列1に基づいて2つのファイルを並べ替える
  2. 以下を 1 行ずつ実行します。
    • ファイル1の列1を使用して、ファイル2の列1から値を取得します。
      1. 見つかった場合は、ファイル1の列2の値をファイル2の列2の値と比較します。
      2. 一致する場合は、列1、2、および3に「確認済み」と書いてファイルを分割します。
      3. 一致するものがない場合は、列1、列2、および「失敗」をファイルごとに作成します。

これにより、2 つの出力ファイルが生成されます。最初のファイルには一致する列 1 と 2 で見つかったすべての項目が含まれ、2 番目のファイルには失敗した列 1 検索または見つかった列 1 が含まれますが、列 2 の位置には一致がないため、デフォルトでは列 1 をキーとして使用します.します。 2列を確認してください。

答え1

次の入力ファイルが与えられた場合:

$ cat in1 in2
Column 1, Column 2
abc     , 123
def     , 234
adf     , 567
Column 1, Column 2
abc     , 123
def     , 234
adf     , 578

まず、それらをソートしてから単一のファイルにリンクできます。

$ sort in1 > in1.sorted; sort in2 > in2.sorted; paste in{1,2}.sorted
Column 1, Column 2  Column 1, Column 2
abc     , 123   abc     , 123
adf     , 567   adf     , 578
def     , 234   def     , 234

awkここではコンマが役に立ちますが、最初にコンマを削除する必要がありますsed

$ paste in{1,2}.sorted | sed s/,//g
Column 1 Column 2   Column 1 Column 2
abc      123    abc      123
adf      567    adf      578
def      234    def      234

その後、次のようにすばやくダンプできますawk

$ paste in{1,2}.sorted | sed s/,//g | awk '$2 == $4 {print $1,"Validated"}; $2 != $4 { print $1,"Failed"}'
Column Failed
abc Validated
adf Failed
def Validated

これはrawを使って行うこともできますawk。ヘッダー行を削除することができ、同じ順序で同じデータに依存しないため、ソートする必要がないという利点があります。

$ awk 'FNR != 1 && NR == FNR {data[$1]=$3} FNR != 1 && NR != FNR {if(data[$1]==$3) {print $1, "Validated"} else {print $1, "Failed"} }' in{1,2}
abc Validated
adf Failed
def Validated

これはいくつかの魔法のawk組み込み変数とそれに関連するトリックに依存します。

  • NR- 処理されたレコードの総数
  • FNR- 総レコード数現在のファイルに扱う
  • FNR != 1- 各ファイルの最初の行をスキップします。 (ヘッダーはデータとして処理されません。)
  • NR != FNR- 最初のファイルを完全に読み込み、その後のファイルを読み始めた後にのみ実行されます。これにより、data2番目のファイルを噛み始めると、テスト用の配列を事前に埋めることができます。

答え2

他の人がこの記事を読んで必要な場合に備えて、次のように問題を解決したと思います。もう一度ありがとうございます。

FNR == NR {
    for (i = 2; i <= NF; i++) { a[i,$1] = $i }
    b[$1];
    next;
}
($1 in b) {                   # check if row in file2 existed in file1
    for (i = 2; i <= NF; i++) {
        if (a[i,$1] == $i)
            printf("%s->col%d: %s vs %s: Valid\n", $1, i-1, a[i,$1], $i);
        else
            printf("%s->col%d: %s vs %s: Failure\n", $1, i-1, a[i,$1], $i);
    }
    delete b[$1];   # delete entries which are processed
}

END {
    for (left in b) {   # look which didn't match
        for (i = 2; i <= NF; i++) 
            printf("%s->col%d: %s vs (blank): Not Equal\n", left, i-1, a[i,left])
    }
}

答え3

使用幸せ(以前のPerl_6)

#! /usr/bin/env raku
    
    #INPUT AND HEADERS:

    my $csv1 = "Veyron1.txt".IO;
    my $csv2 = "Veyron2.txt".IO;

    my $hdr1 = "Key,Value,Verified";
    my $hdr2 = "Key,Value,Failed";

    #HASH STORAGE (Below, beware of `skip`ping header in headerless file!):

    my %csv1; for $csv1.lines.skip.map( *.split(",").map( *.trim)) {
                  %csv1.push: .[0] => .[1]
              };
    my %csv2; for $csv2.lines.skip.map( *.split(",").map( *.trim)) {
                  %csv2.push: .[0] => .[1]
              };

    #SANITY CHECKS:

    die "multiple values per key in file_1" if any(%csv1.values.map: *.elems > 1).so; 
    die "multiple values per key in file_2" if any(%csv2.values.map: *.elems > 1).so;

    #OUTPUT FILE PREP W/ HEADER:

    !("Veyron_output_verified.txt".IO.e) && (my $fh1 = "Veyron_output_verified.txt".IO.open: :a); 
    !("Veyron_output_failed.txt".IO.e) && (my $fh2 = "Veyron_output_failed.txt".IO.open: :a); 

    $fh1.put: $hdr1;
    $fh2.put: $hdr2;

    #OUTPUT LOOP:

    for %csv1.keys.sort -> $id {
       if  %csv2{$id}:exists {
           if  %csv1{$id}  eq  %csv2{$id} {
               $fh1.put: ($id, %csv1{$id}, "verified").join: ",";
           }
           else {
               $fh2.put: ($id, %csv1{$id}, "mismatch").join: ",";
           }
       }
       else {
          $fh2.put: ($id, %csv1{$id}, "absent").join: ",";
       }
    }

    $fh1.close;
    $fh2.close;

これはPerlプログラミング言語の系列であるRakuで書かれたスクリプトです。 Perlと同様に、Rakuにはキー/値データ構造とさまざまなファイル演算子があり、これらの性質の問題を解決するのに理想的です。簡単に:

  • 上部の$-sigiledはファイルハンドル(実際にはオブジェクト)を$csv1意味します。 Rakuではシンボルが変わらないので...$csv2.IO
  • 2つの%署名ハッシュは、%csv1%csv2ファイルから取得したキー/値の格納場所を表します。
  • 空白の切り捨て、ヘッダー操作、および完全性チェックは、実行中のコードに詳細を追加します。
  • 「exists」などのファイル演算子は、.e既存の出力ファイルを上書きしないようにします。ファイルハンドルは、:aを表すオプションで開きます:append
  • 出力ループでの%csv1キーを見つけて%csv2確認してください。対応する文字列eq同じ)values。 「確認済み」、「不一致」、または「存在しない」の3つの文字列のいずれかを返します。
  • 出力は開いている出力ファイルハンドルに1行ずつ追加され、スクリプトの最後で閉じられます。

注:確認したい場合数値的等価物各キーの値は次のとおりです。

%csv1{$id} eq %csv2{$id}そして: %csv1{$id} == %csv2{$id}


出力例(「確認済み」):

Key,Value,Verified
abc,123,verified
def,234,verified

出力例(「失敗」):

Key,Value,Failed
adf,567,mismatch

Leku参考資料:
https://docs.raku.org
https://raku.org

関連Perlスクリプト:
https://www.perlmonks.org/?node_id=805106

関連情報