ルドルフもわたるふもいろいろあってな

Microsoft 365、Power Platform、PowerShellについて調べたことや検証したことなどを投稿します。技術の話は面白い。

【Power Automate】テキスト内で特定の文字が登場した回数を関数で取得する

以前Hiroさんがブログで「Power Automateでデータ操作に親しむための練習問題 その1」という投稿をされていました。(下記リンク参照)
mofumofupower.hatenablog.com


この記事の問題のひとつについてHiroさんの想定解とは違う解きかたを解説したいと思います。対象になるのがこの出題です。

  • フィルター処理の発展編 : "members" を使って年齢に関するヒストグラムを作成する


この解法のメインは掲題の通り「テキスト内で特定の文字が登場した回数を関数で取得する」です。
 
この解法を解説するにあたって、事前に練習問題のブログ記事の紹介についてHiroさんに許可をいただきました。

注意

この記事で解説する手法はHiroさんが出題されている練習問題の別解であり、この手法を推奨する意図はありません。
「こんな配列操作の発想もあるのか。なるほど」という程度に捉えていただければ幸いです。

推奨する意図がない理由はこのやりかたは可読性が低いためです。
個人で使うフローならともかく、複数人で利用するフローを作る場合は繰り返し処理(Apply to each)を用いたやりかたのほうが望ましい場合が多いと思われます。
 

課題の内容

この解法はHiroさんが投稿されている出題を前提としています。まだ問題を読まれていないかたは、まずこちらの投稿を先に目を通すことをお勧めします。
mofumofupower.hatenablog.com

該当の出題「フィルター処理の発展編」以下に転記します。

これらがフローの入力情報です。


そしてこちらがフローによって最終的に出力したいものです。

想定解(と思われるフロー)

別解の解説の前にまずはHiroさんが想定していると思われる解法について触れておきます。なお、今回はこの解法についての詳しい解説は行いません。

この解法は、年代ごと(20代、30代、40代、、)ごとに繰り返し処理(Apply to each)でフィルタ処理を行っています。

フロー図

インプット

フローの実行結果

別解を作成した理由

一言で表すと、Appply to each を使ったフローをApply to each なしの方法に置き換えることができると、そのロジックが"部品"として再利用しやすくなるためです。
 

どうしてApply to each なしで作りかえることが難しいか

今回のフローはApply to each なしで作りかえることが特に難しいフローであるといえます。

その理由は、このフローの繰り返し処理内で使用しているアクションである「フィルタ」処理と「条件に一致した文字列/要素の個数を数える」処理を行うための関数が今現在(2023年3月)存在しないためです。

そのため、「年代ごとにフィルタをしてその個数を数える」という処理をひとつの式の中で完結することが難しいということです。


それをなんとかひとつ式のなかで完結させてApply to eachなしの方法に置き換えたのが今回作成した別解のフローです。
  

別解として作成したフロー

これが別解のフローです。想定解のほうのフローにおけるApply to each 内の処理を2つの「選択」アクションで実現しています。

  

ステップごとの解説

「手動でフローをトリガーします」トリガー

名前の通り、フローを手動で実行するトリガーです。今回はこのトリガーでの入力情報はありません。

 

「作成-集計対象」アクション

このアクションは「データ操作」>「作成」です。このフローの入力情報を定義しています。

 

「選択」アクション

このアクションは「データ操作」>「選択」です。これがひとつめの選択アクションです。この選択アクションでは入力情報である配列が持つ各要素の「10の位」だけを抽出した配列を作成します。

プロパティ

"from": "@outputs('作成-集計対象')",
"select": "@first(string(item()?['age']))"

 

今回のフローで求めるものは各要素がどの年代(20代、30代、40代、、)にあたるかです。つまり、「10の位」の数字のみで判定できます。
そのため、必要なデータである「10の位」の数字のみをこのアクションで抽出します。

入力

出力

 

「選択 2」アクション

このアクションは「データ操作」>「選択」です。このアクションでは各年代の数字が登場した回数を取得します。

プロパティ

"from": "@createArray(2,3,4,5)",
"select": {
"@{concat('age_',mul(item(),10))}": "@sub(length(split(join(body('選択'),''),string(item()))),1)\r\n\r\n"
}

 

まずは 「ひとつめの"選択"アクション」によって出力された配列をjoin関数でひとつのテキストとして結合します。

24333342532432334432

 
例えばこのなかから30代のひとだけを探すとします。その場合は3を区切り文字としてでsplit関数で分割します。


次に、分割したことで生まれた配列の要素の個数を length関数で数えます。下図の場合は個数は 10ですね。


最後にこの個数にsub関数で 1 を引きます。10 - 1 = 9 。この9という数字が「30代のひとの人数」です。


つまり、「テキスト内で特定の文字が登場した回数を関数で取得する」という処理は下記の3つの処理の合わせ技で実現できるということです。

  • 検索対象の文字で分割する (split関数)
  • 出来上がった配列の要素の個数を数える(length関数)
  • その数から1を引きます(sub関数)


この処理がふたつめの選択アクションのインプットの要素の個数だけ実行されます。そしてこの処理によって作成された要素を持つ配列がふたつめの選択アクションの出力となります。


「選択」アクションの本質は繰り返し処理である」という認識があると上記の仕組みが理解しやすいと思います。これについては別記事でも触れていますので、そちらも合わせて参照してください。
wataruf.hatenablog.com
 

このフローをGitHubで公開しました。

フローをGitHubで公開しました。下記リンク先からダウンロードしてください。
github.com
 

今回は以上です。