おはようございます。こんにちは。こんばんは。
ミッドです。
昨日に引き続き、PowerShellでなんやかんやしたいPart2
今回は、2つのCSVファイルでvlookupする方法です。
マイクロソフトのTechnetに良い回答があったので、そちらを参考にしています。
上記で理解できる方は、上記リンクのコードを参照してください。
個人的には、vlookupするcsvファイルに、すでに紐づけるヘッダーが用意されているのが現実的ではないので、ヘッダーの入れ替えを含んだコードを用意しました。
コードはこれだ!!
# 配列変数の定義
$poke = @{}
# 紐づけたいcsvデータの取得
Import-Csv “.\test2.csv” -Encoding Default |
%{$poke[$_.no] = $_.name}
# 新ヘッダーを「test3.csv」に記載
$delimiter = “,”
$new_header = “no”,”type”,”name” -join $delimiter
$new_header | Out-File -Encoding Default “.\test3.csv”
# 紐づけるcsvデータ「test1.csv」を読み込んで、「test_3.csv」に追記
Get-Content “.\test1.csv” | Select-Object -Skip 1 | Out-File -Encoding Default -Append “.\test3.csv”
# ヘッダー変更したtest3.csvを読み込み、vlookupして「fin.csv」に出力
Import-Csv “.\test3.csv” -Encoding Default |
%{$_.name = $poke[$_.no ] ; $_} |
Export-Csv “.\fin.csv” -Encoding Default -NoTypeInformation
exit
材料のCSVはそれぞれ下記となります。
“no”,”type”
“3”,”草・毒”
“4”,”炎”
“2”,”草・毒”
“3”,”草・毒”
“1”,”草・毒”
“6”,”炎・飛行”
“no”,”name”
“1”,”フシギダネ”
“2”,”フシギソウ”
“3”,”フシギバナ”
“4”,”ヒトカゲ”
“5”,”リザード”
“6”,”リザードン”
出力した最終の「fin.csv」は下記のようになります。
“no”,”type”,”name”
“3”,”草・毒”,”フシギバナ”
“4”,”炎”,”ヒトカゲ”
“2”,”草・毒”,”フシギソウ”
“3”,”草・毒”,”フシギバナ”
“1”,”草・毒”,”フシギダネ”
“6”,”炎・飛行”,”リザードン”
では、解説にいってみましょう。
解説
今回の2つのCSVファイルでは、「test1.csv」に「no」にマッチするポケモン名「name」を追記したいです。「no」に紐づくポケモン名(name)は「test2.csv」側にあります。
1.配列の定義
vlookupではCSVを1行ずつ読み込んで処理を行っていくので、最初に空の配列変数を定義しておきます。それが下記部分です。
$poke = @{}
「$poke」は変数名なので、なんでも大丈夫です。「@{}」が空の配列を表します。
2.紐づけたいCSVデータの取得
まずは紐づけたい情報(名前)を1で作った配列に入れ込んでいきます。
Import-Csv “.\test2.csv” -Encoding Default
で「test2.csv」を読み込んで、パイプでつなげて下記の処理をかまします。
%{$poke[$_.no] = $_.name}
これは$pokeの「$_.no(test2のNo)」の項目は、そのNoに紐づくポケモン名だよという配列を作っています。
1行だけ処理を具体的に書くと、「%{$poke[1] = フシギダネ}」ってことです。
これが、$poke[1]~$poke[6]まで処理されていきます。
3.ヘッダーに項目追記
csvファイルは基本的に必要な要素のヘッダーしかなく、vlookupしたいときは異なる仕組みとか、異なる処理で出たデータをマージしたいときなので、今回でいうと名前(name)のヘッダーを追加しておく必要があります。
下記で、区切り文字を変数に代入しています。
$delimiter = “,”
「no」「type」「name」を「,」を区切り文字として、「new_header」変数に入力。
$new_header = “no”,”type”,”name” -join $delimiter
「new_header」変数を、「test3.csv」に出力しています。
$new_header | Out-File -Encoding Default “.\test3.csv”
そして、名前を紐づけたい「test1.csv」を読み込んで、「test3.csv」に追記しているのが、下記部分となります。
Get-Content “.\test1.csv” | Select-Object -Skip 1 | Out-File -Encoding Default -Append “.\test3.csv”
「Select-Object -Skip 1」で元々のヘッダー部分である1行目を飛ばしている点と、Out-Fileの「-Append」が必要な点がみそです。
4.vlookupの実施
ようやくvlookupにたどり着きましたね。
ヘッダーを差し替えた「test3.csv」を読み込み、
Import-Csv “.\test3.csv” -Encoding Default
下記処理で、test3.csvの「nameフィールド」に「$poke[$_.no ]」を入れ込んでいます。
%{$_.name = $poke[$_.no ] ; $_}
$poke[$_.no ]の「[$_.no ]」はtes3.csvの「no」です。
項目2で似たようなことをやりましたが、vlookupは同じ要素に対して検索をかけてマッチした要素を取り出すので、同じ「$_.no」なんですが見ているnoは違うということを意識しておきましょう。
つまり、tes3.csvの名前フィールドは、$poke[test3.csvのno]のポケモン名だよってことです。test3.csvの1行目のnoは「3」なので、$poke[3]のポケモン名=test2.csvで入れ込んだ「フシギバナ」です。
「; $_」は「nameフィールド」にポケモン名を入力した処理の後に、行全体($_)を表示して、下記のコマンドで「fin.csv」に抽出しています。
Export-Csv “.\fin.csv” -Encoding Default -NoTypeInformation
完!!お疲れさまでした。
スクリプト系は解説しようと思うと、めっちゃ文字数使いますね。疲れる(笑)
分かりやすいように各項目でコメントも記載しているつもりですので、どこのコマンドがどういう処理なのかを追っていって頂き、理解を深めて頂ければと思います。
次回からはコードと解説は分けよう(笑)
ではでは