また面白そうな課題をお借りしました。Excel関数の課題ですが、フローで対応してみました。
課題の内容
内容はこちらです。
一応数式が作れたので出題します。
— エクセルの神髄 (@yamaoka_ss) October 11, 2022
【エクセル問題】
・数字が連続して与えられています。
・その中で連続している偶数は順番を逆にして返す。
※奇数はそのまま。 pic.twitter.com/u2xctEe2qN
作成したフロー
アクションの設定を閉じた状態のフロー図
開いた状態のフロー図
実行イメージ
手動トリガーでフローを実行します。
フローが実行されました。
元の配列は下図のアクションで定義しています。
課題の条件通りの出力になりました。
(`・ω・´)シャキーン
このフローのポイント
「一時的なデータを格納する変数」をうまく使うこと
このフローは「元の配列」をインデクサとして繰り返し処理を行っています。
繰り返し処理内で要素の数字が偶数なのか奇数なのかを判定しています。その判定結果によって以下の処理を行っています
ポイントは「一時的なデータを格納する変数」をうまく使うことです。
- 偶数である場合
- 現在のitemを「一時領域」の配列変数に追加
- 奇数である場合
- 「一時領域」に格納している配列を「並び替え後の配列」の配列変数に追加
- 「一時領域」を空の配列で上書き
- 現在のitemを「並び替え後の配列」に追加
繰り返し処理の結果(1回のループごと)
このフローでは1回のループごとの入力と出力を分かりやすいくするために以下のアクションを配置しています。
- 繰り返し処理の最初 ・・・ 繰り返し処理の入力を表示するアクション
- 繰り返し処理の最後 ・・・ 繰り返し処理の出力を表示するアクション
繰り返し処理の結果を1回のループごとに見てみましょう。
1回目
最初のitemは「1」です。このitemは「奇数」です。
そのため、このitemは「並び替え後の配列」に追加します。このときに「一時領域」はまだ空なので「"一時領域"の値を"並び替え後の配列"に追加する」アクションでは何も「並び替え後の配列」に追加されません。
2回目
次のitemは「2」です。このitemは「偶数」です。
そのため、このitemは「一時領域」に追加します。
3回目
次のitemは「4」です。このitemは「偶数」です。
そのため、このitemは「一時領域」に追加します。
4回目
次のitemは「5」です。このitemは「奇数」です。
そのため、現在「一時領域」に格納されている値を降順に並び替えて「並び替え後の配列」に追加します。そのあとに現在のitemを「並び替え後の配列」に追加します。
5回目
次のitemは「6」です。このitemは「偶数」です。
そのため、このitemは「一時領域」に追加します。
6回目
次のitemは「8」です。このitemは「偶数」です。
そのため、このitemは「一時領域」に追加します。
7回目
次のitemは「10」です。このitemは「偶数」です。
そのため、このitemは「一時領域」に追加します。
8回目
最後のitemは「13」です。このitemは「奇数」です。
そのため、現在「一時領域」に格納されている値を降順に並び替えて「並び替え後の配列」に追加します。そのあとに現在のitemを「並び替え後の配列」に追加します。
これで並び替え処理がすべて完了しました。
ステップごとに解説します
ステップごとの解説
「手動でフローをトリガーします」トリガー
名前の通り、フローを手動で実行するトリガーです。今回はこのトリガーでの入力情報はありません。
「作成-元の配列」アクション
このアクションは「データ操作」>「作成」です。
このアクションに記載している式
createArray(1,2,4,5,6,8,10,13)
このアクションでフローが並べ替えを行う対象の配列を作成しています。
「変数を初期化する-並び替え後の配列」アクション
このアクションは「変数」>「変数を初期化する」です。このフローが最終的に出力する配列を格納する変数です。
ここでは空の配列として定義します。
「変数を初期化する-一時領域」アクション
このアクションは「変数」>「変数を初期化する」です。繰り返し処理内で一時的にデータを保存するために使用する変数です。
ここでは空の配列として定義します。
「変数を初期化する-空の配列」アクション
このアクションは「変数」>「変数を初期化する」です。繰り返し処理内で「一時領域」変数をクリアするために使う変数です。
ここでは空の配列として定義します。上書き対象の変数を空の配列で上書きするために使うため、この変数にデータを格納することはありません。
「Apply to each-元の配列」アクション
このアクションは「コントロール」>「Apply to each」です。繰り返し処理を行います。
この繰り返し処理のインデクサとして使用するものは 「作成-元の配列」アクションで作成した配列です。
繰り返し処理内のステップについて解説します。
「作成-このループの入力」アクション
このアクションは「データ操作」>「作成」です。繰り返し処理の入力となるデータを表示します。このアクションはフローの処理を理解しやすくするために配置しています。このアクションを削除しても、フローの最終的な出力には影響はありません。
このアクションに記載している式
現在のitem:@{item()}
偶数か奇数か:@{if(equals(mod(item(),2),0),'偶数','奇数')}
「条件-偶数である」が「はい」の場合
現在のitem が偶数である場合の分岐処理です。
このアクションは「変数」>「配列変数に追加」アクションです。
"name": "一時領域",
"value": "@item()"
「条件-偶数である」が「いいえ」の場合
現在のitem が奇数である場合の分岐処理です。
このスコープ内のアクションは「"一時領域"の配列を並び替えて"並び替え後の配列"に追加する」ことを目的にしています。
また、フローを読みやすくする目的でスコープでアクションを囲んでいます。スコープがなくても処理結果は変わりません。
このアクションは「データ操作」>「作成」アクションです。"一時領域に格納した配列"を降順に並び替えたものを「並び替え後の配列」変数をUnion関数を使ってマージしています。
このアクションに記載している式
"inputs": "@union(variables('並び替え後の配列'),reverse(sort(variables('一時領域'))))"
配列内の要素を並べ替えるために reverse関数とsort関数を使用しています。これらの関数は2022年9月に追加された新しい関数です。
参照:
qiita.com
次のアクションは「変数」>「変数の設定」アクションです。先ほど「作成」アクションで作成した配列で「並び替え後の配列」変数を上書きしています。
このアクションに記載している式
@{outputs('作成-一時領域の配列を並び替えて最終的な配列とマージした変数')}
次のアクションは「変数」>「変数の設定」アクションです。先ほど「一時領域」の変数を空の配列で上書きしています。このアクションでスコープ内の処理は完了です。
このアクションに記載している式
@{variables('空の配列')}
次のアクションは「変数」>「配列変数の追加」アクションです。現在のitemを「並び替え後の配列」変数に追加します。
このアクションに記載している式
@{item()}
「作成-このループの出力」アクション
このアクションは「データ操作」>「作成」です。繰り返し処理の出力となるデータを表示します。このアクションはフローの処理を理解しやすくするために配置しています。このアクションを削除しても、フローの最終的な出力には影響はありません。
このアクションに記載している式
一時領域:@{variables('一時領域')}
並び替え後の配列:@{variables('並び替え後の配列')}
「作成-並び替え後の配列」アクション
このアクションは「データ操作」>「作成」アクションです。
このアクションに記載している式
@{variables('並び替え後の配列')}
最後に
このフローの最も大きな解説ポイントは「一時データを保存する変数を用いることによって繰り返し処理のおける"要素の並び"を条件判定の対象としていること」です。
繰り返し処理の1回ごとの入力情報は基本的にはitemのみです。
ですが、itemだけでは今回の課題のように「配列内に特定の条件(= ここでは"偶数であること")に一致する要素が複数回連続で登場した」ことを検知することができません。
一時データを保存する変数を用いることで、itemが「奇数」だった場合に"一時データとしてよけておいた要素に対して処理を行う"ことを実現しています。
今回のフローで使用した、一時データを使用した手法は以前解説した「CSV文字を1文字ずつ解析するフロー」で用いた手法と同じ仕組みです。興味のあるかたはこちらの記事を参照してください。
wataruf.hatenablog.com
今回は以上です。