Power BI Desktop や Excel のクエリ エディターでデータの変換や加工をしていると、"each" キーワードと "_"(アンダースコア)が 式に使用されている。さて、これは何か?というお話。クエリ エディターで生成された Power Query(M言語)を理解し、もっと複雑な処理(適用するステップ)をしたい場合には必要なことなので。
ボタンポチポチだけの作業で済むのなら気にすることはないけれども。
どのように使われているか
例えば、Table.AddColumn 関数 - Power Query M function reference
Table.AddColumn(
table as table,
newColumnName as text,
columnGenerator as function, // <--- ここで使用されている
optional columnType as nullable type
) as table
テーブルに列を追加するとき、その追加列の値を 関数型( type function )の引数 : columnGenerator で指定している。
"テーブル" に対し "追加列" という列を追加し、その値をそれぞれ 0 にするというステップでは、"each" がでてくる。
Table.AddColumn( テーブル, "追加列", each 0 )
テーブル から空白行を除外するステップを適用するとき、"each" と "_"(アンダースコア) が使われている。
Table.SelectRows(
PreviousStep_table,
each not List.IsEmpty(
List.RemoveMatchingItems(
Record.FieldValues(_),
{"", null}
)
)
)
"each" キーワード と "_"(アンダースコア)
"each" と "_"(アンダースコア) はセットで使用するが、"_"(アンダースコア) は省略されることがある。
each
そのまんまの意味で each です。"それぞれ" と考えてよさそう。
- リスト(list)を扱う関数の場合、リストのアイテム(item)それぞれに処理を行う
- テーブル(table)を扱う関数の場合、行(row)それぞれに処理を行う
"_"(アンダースコア)
リスト ( list )
List.Transform( {1, 2, 3}, each _ + 1 ) = {2, 3, 4} // true
List.Transform(
list as list,
transform as function
) as list
each _ + 1 の "_"(アンダースコア)は、リストアイテムそれぞれを処理するときそのアイテムを表す変数名。
テーブル ( table )
Table.SelectRows( テーブル , each [列1] > 3)
Table.SelectRows(
table as table,
condition as function
) as table
ここには "_"(アンダースコア)がない。これは速記簡略されていると考えればよくて、
Table.SelectRows( テーブル , each _[列1] > 3 )
each _[列1] > 3 の "_"(アンダースコア)は、テーブル各行でそれぞれを処理するときその行を表す変数名。
そして、そのデータ型は record に特定。なので、フィールドをルックアップする記述は、"[ ]"(ブラケット)を使って _[ column-name ]
let
Source = #table(
type table [列1 = any, 列2 = any],
{
{"A", 1}, {"A", 2}, {"B", 3}, {"B", 4}
}
),
AddedCustom = Table.AddColumn(
Source,
"IsType.Record",
each Type.Is( Value.Type( _ ), Record.Type ) )
in
AddedCustom
shorthand
Power Query での関数の記述は、(x) => x + 10 という感じなのだけど、テーブルやリスト扱う関数では 速記簡略する記述が可能なことが多い。そして中の人は多く使っている。
let
Source = #table(
type table [列1 = any, 列2 = any],
{
{"A", 1}, {"A", 2}, {"B", 3}, {"B", 4}
}
),
TrimmedText = Table.TransformColumns( Source, { "列1", Text.Trim } ) // ココ、トッテモ shorthand
in
TrimmedText
変換対象の値がひとつに特定でき、かつ、変換関数の必須引数がひとつなのでとてもシンプルな記述になっているわけで、
Table.TransformColumns( Source, { "列1", each Text.Trim( _ ) } )
とも記述できるし、
Table.TransformColumns( Source, { "列1", ( CurrentString ) => Text.Trim( CurrentString ) } )
とも記述できる。
変換関数の必須の引数が複数になるときや、オプション引数にも値を渡す場合には、"each" キーワード と "_"(アンダースコア) を使用することになるんですけど。