Power BI Desktop や Excel 利用できる Power Query で list がもっとうまく使えたらなぁと最近よく思うんです。繰り返したい処理とかでも使えそうですし。そう思った事の発端は、
- Using List.Generate() To Make Multiple Replacements Of Words In Text In Power Query
- Nested Loop with List.Generate in Power Query
とかで MSDN:List.Generate を調べていたからなんだけど、ここまで複雑なことでなくても list を扱えれば便利じゃないかなと考えた次第。よく使う Power Query の関数なかでも引数の型が list なのもそこそこありますしね。
クエリ エディターでの作業の多くは Table に対してのことが多いのだけど、あれこれしているうちに、これって列の追加や値の変換とかでは解決できないんじゃね?とか手詰まりに近いことあったりするんですね。複雑な処理はユーザー定義関数を用意したりして工夫をしたりはするけれども。で、List.Generate を使って何かを解決する前に List と関連する関数にちょっと注目してみた。
List は { } で表現
簡単なところから。{1, 2, 3}
は、すべてのリストアイテムが数値(number)の List。
{1, "A", 3}
{
{1, "A"},
{2, "B"}
}
リストアイテムは型は any で特定されなくてもよいのでネストしたりしても可。型が record や table というのもよく見かけることになるかもしれない。{1, 2, 3} = {1, 2, 3} // true
{1, 2, 3} <> {1, 3, 2} // true
{10, 20, 20} = {10, 20, 10 + 10 } // true
{"A", "B"} & {"C"} = {"A", "B", "C"} // true
重要なのはアイテムの順番ですね。ほか便利な記法としてはシーケンサ(..)というの使えます。ただし、値や文字コードが昇順になっていないとリストアイテム数が 0 の List になってしまいます。{1 .. 5} = {1, 2, 3, 4, 5} // true
{"A" .. "C"} = {"A", "B", "C"} // true
List.Count({3 .. 1}) = 0 // true
リストアイテムを参照する { } と間違いのないように。
{"A", "B", "C"}{1} = "B" // true
便利そうなので使ってみた組合せ
Text.ToList:文字列を list に変換Text.Combine:アイテム(text)の list からひとつの文字列に結合
List.ToList("ABCDE") = {"A", "B", "C", "D", "E"} // true
Text.Combine({"A", "B", "C", "D", "E"}) = "ABCDE" // true
文字列を list に変換 → すべてのアイテム(text)に対し List.Transform などで処理 → 再び結合すれば置換のような処理になる。単純な置換であれば、List.ReplaceMatchingItems でよいかな。List.ReplaceMatchingItems({"A", "B", "C"}, {{"A", 1}, {"C", 3}}) = {1, "B", 3} // true
リストアイテムにマッチするものを置換してくれるのだけど、引数がリスト{OldText, NewText}のリストだから、Text.Combine(
List.ReplaceMatchingItems(
Text.ToList(
"平成29年6月15日"
),
List.Zip(
{{"0".."9"}, {"0".."9"}}
)
)
) = "平成29年6月15日" // true
という感じに表現できてよいかも。もう少し範囲を拡げて 全角英数記号などを半角に変換するならこんな感じでも。
(Source as text) as text =>
let
Combi = List.Zip(
{
{Character.FromNumber(0x3000), "!".."~"},
{Character.FromNumber(0x20), "!".."~"}
}
),
TextList = List.ReplaceMatchingItems(Text.ToList(Source), Combi)
in
Text.Combine(TextList)