PowerAutomateでフローを構築、SharePointやTeamsから取得したデータを処理するなかで、意外と頻繁に発生する配列のフラット化のニーズ。
直近もいくつかのフローでそれぞれのコンテキストに応じたステップ&コードを記述したものを、今回一般化して整理してみました。
Problem
2次元配列のフラット化を行いたいが、それを簡単に行える式関数が提供されていない。
「それぞれに適用」(Apply to each)は使いたくない。「それぞれに適用」を使用するとアクション実行数が増え、性能が低下するため。
またOfficeScriptsも使いたくない。これも性能が低下するため。
Solution
「選択」アクションや「作成」アクションと式関数を組み合わせて工夫する。
# | 配列の様態 | フラット化方法 | 前提条件 | ステップ数 |
---|---|---|---|---|
1 | シンプルな2次元配列 | concatで統合 | - | 2 |
2 | 〃 | unionで統合 | 外側配列の要素数は決まっている かつ 重複は削除してよい | 1 |
3 | 〃 | replaceで統合 | 配列要素が文字列でない もしくは 文字列だが角括弧は含まない | 1 |
4 | 配列要素オブジェクトのプロパティに配列 | concatで統合 | - | 2 |
#1 シンプルな2次元配列 - concatで統合
ターゲットとなる配列がシンプルな2次元配列のケース。
もっとも汎用的な処理方法。
配列イメージ
[ [1, 2, 3], [4, 5], [5, 6, 7, 8, 9] ]
あるいは
[ ["foo"], ["foo", "bar", "baz"], [], ["foo", "bar"] ]
フロー
- 選択アクション。配列の要素(内側の配列)をJSON文字列化したあと、前後の
[...]
を削除してCSV化(例:["[1,2,3]", "[4,5]", "[5,6,7,8,9]"]
→["1,2,3", "4,5", "5,6,7,8,9"]
) - 作成アクション。それらのCSVをカンマで連結して1つの大きなCSV化したあと、前後に
[...]
を付与してJSONとしてパース(例:"1,2,3,4,5,5,6,7,8,9"
→"[1,2,3,4,5,5,6,7,8,9]"
→[1,2,3,4,5,5,6,7,8,9]
)
選択アクションのパラメーター
「元」はもちろん2次元配列。
「マップ」は @substring(string(item()),1,sub(length(string(item())),2))
。
作成アクションのパラメーター
「入力」は @json(concat('[',join(body('選択'),','),']'))
。
#2 シンプルな2次元配列 - unionで統合
これもターゲットとなる配列がシンプルな2次元配列のケース。
ただし外側の配列の要素数が分かっている場合。
そして統合過程で重複する要素は削除されても問題ない場合。
フロー
- 作成アクション。添字を使用して内側の配列を取り出して、それらの集合和を求める(例:
[1, 2, 3] ∪ [4, 5] ∪ [5, 6, 7, 8, 9] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
)。
作成アクションのパラメーター
「入力」は、例えば要素数が4固定の場合:
@{union(
<ここに2次元配列>[0],
<ここに2次元配列>[1],
<ここに2次元配列>[2],
<ここに2次元配列>[3]
)}
要素数が0~4の範囲の場合:
@{union(
coalesce(<ここに2次元配列>?[0],json('[]')),
coalesce(<ここに2次元配列>?[1],json('[]')),
coalesce(<ここに2次元配列>?[2],json('[]')),
coalesce(<ここに2次元配列>?[3],json('[]'))
)}
#3 シンプルな2次元配列 - replaceで統合
これもターゲットとなる配列がシンプルな2次元配列のケース。
配列要素が文字列でない場合。
もしくは、文字列だが角括弧は含まない場合。
フロー
- 作成アクション。2次元配列をJSON文字列化したあと、角括弧を文字列置換、その後JSONとしてパース(例:
[[1, 2, 3], [4, 5], [5, 6, 7, 8, 9]]
→"[[1,2,3],[4,5],[5,6,7,8,9]]"
→"[1,2,3,4,5,5,6,7,8,9]"
→[1, 2, 3, 4, 5, 5, 6, 7, 8, 9]
)。
作成アクションのパラメーター
「入力」は
json(
replace(
replace(
replace(
string(<ここに2次元配列>),
'[[',
'['
),
']]',
']'
),
'],[',
','
)
)
#4 配列要素オブジェクトのプロパティに配列 - concatで統合
パッと見、複雑に思えるかもしれないが、やっていることは#1とほぼ同じ。
配列イメージ
外側配列の要素はオブジェクトで、そのオブジェクトのプロパティとして内側配列が存在
[
{ "foo": 123, "bar": [{"baz": "a"}, {"baz": "b"}, {"baz": "c"}] },
{ "foo": 456, "bar": [{"baz": "d"}, {"baz": "e"}] },
{ "foo": 789, "bar": [{"baz": "e"}, {"baz": "f"}, {"baz": "g"}, {"baz": "h"}] }
]
フロー
- 選択アクション。配列の要素のプロパティ(内側の配列)をJSON文字列化したあと、前後の
[...]
を削除してCSV化 - 作成アクション。それらのCSVをカンマで連結して1つの大きなCSV化したあと、前後に
[...]
を付与してJSONとしてパース
選択アクションのパラメーター
「元」はもちろん2次元配列。
「マップ」は @substring(string(item()['bar']), 1, sub(length(string(item()['bar'])), 2))
。
作成アクションのパラメーター
「入力」は @json(concat('[', join(body('選択'), ','), ']'))
。