コルネの進捗や備忘録が記されたなにか

進捗や成果物や備忘録てきななにかを雑に更新していきます。

Power Automate でループなしでデータのソートを行う


スポンサードリンク

はじめに

この記事ではPower Automate で取得したデータをループなしでソート、また、N番目のデータをループなしで取得する方法を纏めています。

Power Automate ではJSON 形式での取得データが行われます。
その取得したデータをソートしたりN番目のデータを取得したい。といった場合があるかと思います。

ただし、現在Power Automate の関数ではいまだにSort 関数のようなものが提供されていません。

docs.microsoft.com

そこで今回は自力でPower Automate でソートを行ってみようと思います。
ただし、Apply to each などでのループ処理は行いません。

ソートアルゴリズムアルゴリズムと要素数によっては計算量が膨大になってしまうからです。
詳しく知りたい方は、「ソートアルゴリズム 計算量」などで調べてみてください。

データ操作

データを昇順ソートさせる

まずは元となるデータを用意します。

"作成"アクションでJSON データを用意します。

f:id:koruneko:20211128034435p:plain

入力

[
  {
    "Name": "Tom",
    "Score": 50,
    "Class": "A"
  },
  {
    "Name": "Jun",
    "Score": 75,
    "Class": "A"
  },
  {
    "Name": "Kei",
    "Score": 64,
    "Class": "A"
  },
  {
    "Name": "Riko",
    "Score": 89,
    "Class": "B"
  },
  {
    "Name": "Hana",
    "Score": 34,
    "Class": "B"
  },
  {
    "Name": "Miyu",
    "Score": 75,
    "Class": "B"
  }
]

上記データの Score でソートを行いたいと思います。

データ操作を行うにあたり、データがオブジェクトリストとなっているとデータ操作ができない(後述のやり方では対象データにアクセスできない)のでソートを行いたいフィールドのみ抽出してあげます。

"選択"アクションを使って Score だけを抽出します。

f:id:koruneko:20211128035416p:plain

開始

@{outputs('作成')}

マップ

@item()?['Score']

これにより以下のような結果が得られます。(* 未加工入力の例です。)

{
    "body": [
        50,
        75,
        64,
        89,
        34,
        75
    ]
}

こちらを昇順ソートさせます。

これには"アレイのフィルター処理"を利用します。

f:id:koruneko:20211128040827p:plain

差出人(from)

range(min(body('Score')), add(sub(max(body('Score')), min(body('Score'))), 1))

条件(where)

contains(body('Score'), item())

"差出人"の訳どうにかならないですかね。元(英語)だと"From"です。

ロジックについて解説します。

fromにはソート順を定義しています。
range 関数range(A, B) のようにすると、整数Aから始まる整数Bまでの配列を返します。

開始の数はソート対象のフィールドの最小値であり、終値はソート対象の最大値であるので、min 関数max 関数を利用します。
ただし、range 関数はBまでの値を返すのではなく、Aから始まるB個の増分1で連続する数値を返す。という点に注意が必要です。

よって終値は"最大値 - 最小値 + 1"とする必要があります。

これにより以下のようなfrom を得ることができます。

[
    34,
    35,
    36,
    37,
    38,
    39,
    40,
    41,
    42,
    43,
    44,
    45,
    46,
    47,
    48,
    49,
    50,
    51,
    52,
    53,
    54,
    55,
    56,
    57,
    58,
    59,
    60,
    61,
    62,
    63,
    64,
    65,
    66,
    67,
    68,
    69,
    70,
    71,
    72,
    73,
    74,
    75,
    76,
    77,
    78,
    79,
    80,
    81,
    82,
    83,
    84,
    85,
    86,
    87,
    88,
    89
]

これで数値が昇順で設定された配列を作成することができました。

あとはフィルタ条件では、ソートを行いたいフィールドと作成された配列の共通部を順に設定していけばよいです。

ソート対象は先ほど"選択"アクションで作成した結果を利用します。
body('Score')

条件は右辺の値を含む左辺の結果が欲しいので"次の値を含む"を利用します。

含む値は、fromの結果を順に取得してもらいたいので、 item() を利用します。

これにより、以下のようにソートされた結果が得られます。

{
    "body": [
        34,
        50,
        64,
        75,
        89
    ]
}

気が付いた方もいらっしゃるかもしれませんが、この方法ではソート対象フィールドに重複した値がある場合は想定している結果が得られない可能性があります。

また、ソート対象フィールドに負の数値がある場合や小数点を含む場合は適宜、正の整数に変換する操作が必要があることに注意してください。

また、このやり方では降順ソートができません。。。
なにかいい方法ないかな

N番目の情報の取得

続いて先ほどソートを行った結果に基づいてN番目のデータを取得してみたいと思います。

この処理にも"アレイのフィルター処理"を利用します。

f:id:koruneko:20211128050020p:plain

From

outputs('作成')

Where

equals(item()?['Score'], body('昇順ソート')?[3])

フィルタ操作は元データに対して行うのでFrom には上記のように設定しています。

検索条件では、元データのソートを行いたいフィールドと昇順ソートした結果のN番目の値が一致した場合。としています。
なお、こちらの配列は0から始まるので、3と設定した場合は4番目に小さい値が存在するデータが取得されることに注意してください。

もしN番目に小さい値ではなくN番目に大きい値を取得したい場合は

equals(item()?['Score'], body('昇順ソート')?[sub(length(body('昇順ソート')), 1)])

という風にソート結果の"配列数 - (N + 1)"としてください。
+ 1 しているのは、0から始まっているからですね。

これにより以下のような結果が取得できます。

[
  {
    "Name": "Riko",
    "Score": 89,
    "Class": "B"
  }
]

データが重複していた場合は以下のように重複結果をきちんと取得できます。

{
    "body": [
        {
            "Name": "Jun",
            "Score": 75,
            "Class": "A"
        },
        {
            "Name": "Miyu",
            "Score": 75,
            "Class": "B"
        }
    ]
}

おわりに

以上。Power Automate でのループなしでソートとN番目のデータの取得方法でした。

工夫次第でこんなこともできるわけではありますが、標準でソート関数が実装されると嬉しいですね。


スポンサードリンク