Power Query M 式言語 カスタム関数作成2(List.Generate使う)
いくつか練習で作成しました。具体的に使える状況が
どんなものかはよくわからないですが、なにかに使えるといいですね。(2022/3/28)
⑤だけ必要があって作りました。(2022/4/3)
①グループ内の最大値がある行だけにするカスタム関数
②(List.Generateを使って)今日から指定日数分の
曜日付きカレンダーを作るカスタム関数
③指定テーブルの列並び順を逆転するカスタム関数
④指定テーブルの列名を左から昇順の番号にするカスタム関数
⑤指定テーブルを1行飛ばしに表示させるカスタム関数
①グループ内の最大値がある行だけにするカスタム関数
let
Result = #table(
type table[Info = text, ごはん = text, 価格 = number, Date = date],
{
{"A", "寿司(最古/最高)", 1000, #date(2018, 1, 1)},
{"A", "焼き肉", 900, #date(2020, 1, 1)},
{"A", "ラーメン(最新/最安)", 800, #date(2022, 1, 1)},
{"B", "クッキー(最新/最高)", 700, #date(2019, 1, 1)},
{"B", "ブールドネージュ(最古/最安)", 600, #date(2017, 1, 1)},
{"C", "えび天(最古/最高)", 500, #date(2020, 1, 1)},
{"C", "チョコレート", 400, #date(2023, 1, 1)},
{"C", "茶碗蒸し", 300, #date(2025, 1, 1)},
{"C", "プリン(最新/最安)", 200, #date(2027, 1, 1)},
{"D", "餅", 100, #date(2000, 1, 1)}
}
)
in
Result
ABCDでグループ化して、最高値のレコードを取る場合の関数
それぞれ(最高)がついているものが取得できれば成功です。
(Dは1個しかないので絶対に餅)
let
/* **GetGroupMax**
tblで指定したテーブルに、groupColumnNameという名前の列でグループ化した
valueColumnName中のデータが最大の行を取得する
*/
Result = (tbl as table, groupColumnName as text, valueColumnName as text) =>
let
Grouped = Table.Group(tbl, { groupColumnName }, {{ "Grouped", each List.Max(Table.Column(_, valueColumnName))}}),
Merged = Table.NestedJoin(tbl, { groupColumnName, valueColumnName }, Grouped, { groupColumnName, "Grouped" }, "Merged", JoinKind.Inner),
Cleaned = Table.RemoveColumns(Merged, { "Merged" })
in
Cleaned
in
Result
取れました。(関数名はGetGroupMax)
List.Maxの代わりにList.Minを使えば最小値も取れました。
②今日から指定日数分の曜日付きカレンダーを作るカスタム関数
let
Result = (dates as number) =>
let
firstDay = DateTime.Date(DateTime.LocalNow()),
Lists = List.Generate(
() => [dateNo = 0, day = null, weekday = null], // initial
(row) => row[dateNo] <= dates, // condition
(row) => [
dateNo = row[dateNo] + 1,
day = Date.AddDays(firstDay, row[dateNo]),
weekday = Date.ToText(day, "ddd")
], // next 1日ずつ足していく。row[xx]にした場合は、前レコードでxxは同じレコード
(row) => [ 日付 = row[day], 曜日 = row[weekday] ]
), // selector 番号はいらないので日付と曜日だけselect
Result = Table.FromRecords(
List.Skip(Lists, 1)
)
in
Result
in
Result
initialとnextに同じことを2回も書きたくなかったのでSkip使いました。他にいい方法ないのでしょうか。(Skip使わずに最初から詰めて作りたい)
結果はうまく取れていそうでした。(この部分を書いている日は2022/3/23)
③指定テーブルの列並び順を逆転するカスタム関数
let // 適当な結果試し用のテーブル
Result = #table(
type table[あ = text, い = text, う = number, え = number],
{
{"A", "あ", 5, 50},
{"A", "あ", 5, 50},
{"A", "あ", 5, 50}
}
)
in
Result
let
/* **Table.ReverseColumns**
tblで指定したテーブルの列を逆順にして返す
*/
Result = (tbl as table) =>
let
columnNames = Table.ColumnNames(tbl),
reverseColumnNames = List.Reverse(columnNames),
ReverseColumns = Table.SelectColumns(tbl, reverseColumnNames)
in
ReverseColumns
in
Result
④指定テーブルの列名を左から昇順の番号にするカスタム関数
※テーブルは③で作ったものを使用
let
/* **Table.RenameColumnsByNumber**
tblで指定したテーブルの列を番号にして返す(左から昇順)
*/
Result = (tbl as table) =>
let
columns = Table.ColumnCount(tbl),
names = Table.ColumnNames(tbl),
numberList = List.Generate(() => [i = 0, columnNameFrom = "", columnNameTo = ""], // initial
(row) => row[i] <= columns, // condition
(row) => [
i = row[i] + 1,
columnNameFrom = names{i - 1},
columnNameTo = "適当なPrefix" & Text.From(i) // ここを適当にいじればprefixもつけられる
], // next
(row) => { row[columnNameFrom], row[columnNameTo] }), // selector
Renamed = Table.RenameColumns(tbl, List.Skip(numberList, 1), MissingField.Ignore)
in
Renamed
in
Result
⑤指定テーブルを1行飛ばしに表示させるカスタム関数
let
Result = (tbl as table) =>
let
/* 1行ごとに挿入するための空のレコードを作る
newキーワードみたいなの無いんですか?
*/
colCount = Table.ColumnCount(tbl),
nullValues = List.Generate(() =>
[i = 0, value = null], // initial
(row) => row[i] < colCount, // condition
(row) => [
i = row[i] + 1,
value = null
], // next
(row) => row[value] // selector
),
nullRecord = Record.FromList(nullValues, Table.ColumnNames(tbl)),
/* もとのテーブルの1行飛ばしで取得する
*/
rowCount = Table.RowCount(tbl),
lists = List.Generate(() =>
[i = 0, rowNo = -1, rowData = null], // initial
(row) => row[rowNo] < rowCount, // condition
(row) => [
i = row[i] + 1,
rowNo = row[rowNo] + Number.Mod(i, 2),
rowData =
if
Number.Mod(i, 2) = 0
then
nullRecord
else
tbl{rowNo}
], // next
(row) => row[rowData] // selector
),
Result = Table.FromRecords(List.Skip(lists, 1))
in
Result
in
Result
おわり。
row[i]…前の行のiで、i…今の行のiと、
[](フィールド名的なものでアクセスする際に使う)と
{}(行番号的なものでアクセスする際に使う)の使い分けは忘れそう…
なので今ここに書きました。