1. gyoon

    Posted

    gyoon
Changes in title
+powershellでCSV等の区切り文字があるファイルの数値列の合計を計算する
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,91 @@
+あるファイルがあり、以下のような中身だったとします。
+これの3列目の数値の合計を計算する方法を考えます。
+
+
+aaaa,bbbb,200,cccc
+dddd,eeee,300,ffff
+gggg,hhhh,400,iiii
+jjjj,kkkk,500,llll
+
+linuxの場合は、awkを使って以下のように計算できます。
+
+```bash
+# cat test1a.txt | awk -F, '{sum += $3} END {print sum}'
+1400
+```
+
+powershellの場合は以下で3列目の合計が計算できます。
+
+```ps1
+
+Get-Content .\test3.txt | %{$sum += [int]$_.split(",")[2]};$sum
+```
+
+もしくは
+
+```ps1
+Import-Csv .\test3.txt -header(1..4) | Select-Object "3" | %{$sum += [int]$_.3};$sum
+```
+
+**パターン1の解説**
+%はforeachのエイリアスです。
+foreach中は``$_``に一行づつ代入されます。
+まず各行は,で区切られているので、``split``で分割します。
+分割した行は配列として扱われます。
+配列でいうとカンマ区切りの3列目はインデックス[2]です。
+``$sum``に``$_``を加算していき、最後に``$sum``を表示します。
+``$_``はそのままだと文字列として扱われるため、[int]でキャストしています。
+区切り文字がカンマ以外の場合は、splitでその区切り文字を指定すればすぐに応用できます。
+
+コマンドライン上で計算する場合は、このパターン1のほうが覚えやすいと思います。
+
+
+**パターン2の解説**
+Import-CSVコマンドレットを使います。
+このコマンドレットはCSV扱うためのものです。
+デフォルトだと先頭行が列名として扱われてしまうため、-headerオプションで列名を作成しています。
+select-object以降を消して実行すると以下の結果になります。
+列ごとにオブジェクト化されるようです。
+
+```ps1
+
+PS E:\work> Import-Csv .\test3.txt -header(1..4)
+
+1 2 3 4
+- - - -
+aaaa bbbb 200 cccc
+dddd eeee 300 ffff
+gggg hhhh 400 iiii
+jjjj kkkk 500 llll
+```
+
+Select-Objectで列名3を取得しています。
+
+$_.3で計算しているのは、以下のためです。
+
+``%{$_ | GetMember}``の結果
+
+```ps1
+Name MemberType Definition
+---- ---------- ----------
+Equals Method bool Equals(System.Object obj)
+GetHashCode Method int GetHashCode()
+GetType Method type GetType()
+ToString Method string ToString()
+3 NoteProperty System.String 3=200
+```
+``$_.Get-Tyep()``の結果
+
+```ps1
+
+IsPublic IsSerial Name BaseType
+-------- -------- ---- --------
+True False PSCustomObject System.Object
+```
+
+つまり``$_``のままだとPSCustomObjectとして扱われるため、この中のプロパティである3に
+実際の数値がString型で格納されているため参照しているわけです。
+
+パターン2で使用するimport-csvはすべてのカラムをオブジェクトに入れてくれるので
+powershellスクリプトなどで、どのカラムも計算対象・処理対象になる等の場合に使用する場合は便利だと思います。
+コマンドライン上である列の値の合計だけ出したいときはパターン1の単純にsplitで区切るやり方が簡単かと思います。