【初心者向け】Power Automate データ操作 練習帳

# はじめに
[Power Automateのデータ操作](https://learn.microsoft.com/ja-jp/power-automate/data-operations#use-the-select-action)は非常に強力な機能です。

https://learn.microsoft.com/ja-jp/power-automate/data-operations

使いこなすことで、様々なコネクターのアクションから返されるJSONを、自分やビジネスの用途に合わていくことができます。
とはいえ、使いこなすためには、練習が不可欠。

下記に練習用のJSON配列入力を、ChatGPTに作成してもらいました。

**私と一緒に練習してみましょう！**

:::note info
データ操作 練習帳とうたっていますが、私の知見と調査の範囲内ですので、より良い方法はありえます。
コメントで助言をいただければ幸いです。
:::

## 練習用JSON
ChatGPTにて作成してもらいました。

- 数値(`integer`)
- 数値(`float`)
- Boolean(`boolean`)
- 文字列(`string`)
    - 日付文字列(`string`)
- オブジェクト(`object`)
- 配列(`array`)

上記の要素を加えています。

<details><summary>JSONを参照する際は、折りたたみを解除してください。</summary>

```json:練習用JSON
[
  {
    "id": 1,
    "name": "Alice",
    "age": 25,
    "isActive": true,
    "roles": [
      "Admin",
      "User"
    ],
    "address": {
      "street": "123 Main St",
      "city": "Springfield",
      "zip": "12345"
    },
    "lastLogin": "2024-05-01T08:00:00Z",
    "floatValue": 25.5
  },
  {
    "id": 2,
    "name": "Bob",
    "age": 30,
    "isActive": false,
    "roles": [
      "User"
    ],
    "address": {
      "street": "456 Elm St",
      "city": "Shelbyville",
      "zip": "67890"
    },
    "lastLogin": "2024-05-02T09:00:00Z",
    "floatValue": 30.5
  },
  {
    "id": 3,
    "name": "Charlie",
    "age": 35,
    "isActive": true,
    "roles": [
      "Admin",
      "Manager",
      "User"
    ],
    "address": {
      "street": "789 Oak St",
      "city": "Ogdenville",
      "zip": "54321"
    },
    "lastLogin": "2024-05-03T10:00:00Z",
    "floatValue": 35.5
  },
  {
    "id": 4,
    "name": "David",
    "age": 28,
    "isActive": false,
    "roles": [
      "User"
    ],
    "address": {
      "street": "321 Pine St",
      "city": "Springfield",
      "zip": "12345"
    },
    "lastLogin": "2024-05-04T11:00:00Z",
    "floatValue": 28.5
  },
  {
    "id": 5,
    "name": "Eve",
    "age": 22,
    "isActive": true,
    "roles": [
      "User"
    ],
    "address": {
      "street": "654 Maple St",
      "city": "Shelbyville",
      "zip": "67890"
    },
    "lastLogin": "2024-05-05T12:00:00Z",
    "floatValue": 22.5
  },
  {
    "id": 6,
    "name": "Frank",
    "age": 40,
    "isActive": true,
    "roles": [
      "Manager",
      "User"
    ],
    "address": {
      "street": "987 Birch St",
      "city": "Ogdenville",
      "zip": "54321"
    },
    "lastLogin": "2024-05-06T13:00:00Z",
    "floatValue": 40.5
  },
  {
    "id": 7,
    "name": "Grace",
    "age": 32,
    "isActive": false,
    "roles": [
      "Admin",
      "User"
    ],
    "address": {
      "street": "741 Cedar St",
      "city": "Springfield",
      "zip": "12345"
    },
    "lastLogin": "2024-05-07T14:00:00Z",
    "floatValue": 32.5
  },
  {
    "id": 8,
    "name": "Hank",
    "age": 29,
    "isActive": true,
    "roles": [
      "User"
    ],
    "address": {
      "street": "852 Walnut St",
      "city": "Shelbyville",
      "zip": "67890"
    },
    "lastLogin": "2024-05-08T15:00:00Z",
    "floatValue": 29.5
  },
  {
    "id": 9,
    "name": "Ivy",
    "age": 27,
    "isActive": true,
    "roles": [
      "Admin",
      "User"
    ],
    "address": {
      "street": "963 Cherry St",
      "city": "Ogdenville",
      "zip": "54321"
    },
    "lastLogin": "2024-05-09T16:00:00Z",
    "floatValue": 27.5
  },
  {
    "id": 10,
    "name": "Jack",
    "age": 45,
    "isActive": false,
    "roles": [
      "Manager"
    ],
    "address": {
      "street": "159 Spruce St",
      "city": "Springfield",
      "zip": "12345"
    },
    "lastLogin": "2024-05-10T17:00:00Z",
    "floatValue": 45.5
  }
]
```

</details>

■ テーブルバージョン

| id (integer) | name (string) | age (integer) | isActive (boolean) | roles (array) | street (string) | city (string) | zip (string) | lastLogin (string) | floatValue (number) |
|---|---|---|---|---|---|---|---|---|---|
| 1 | Alice | 25 | true | Admin,User | 123 Main St | Springfield | 12345 | 2024-05-01T08:00:00Z | 25.5 |
| 2 | Bob | 30 | false | User | 456 Elm St | Shelbyville | 67890 | 2024-05-02T09:00:00Z | 30.5 |
| 3 | Charlie | 35 | true | Admin,Manager,User | 789 Oak St | Ogdenville | 54321 | 2024-05-03T10:00:00Z | 35.5 |
| 4 | David | 28 | false | User | 321 Pine St | Springfield | 12345 | 2024-05-04T11:00:00Z | 28.5 |
| 5 | Eve | 22 | true | User | 654 Maple St | Shelbyville | 67890 | 2024-05-05T12:00:00Z | 22.5 |
| 6 | Frank | 40 | true | Manager,User | 987 Birch St | Ogdenville | 54321 | 2024-05-06T13:00:00Z | 40.5 |
| 7 | Grace | 32 | false | Admin,User | 741 Cedar St | Springfield | 12345 | 2024-05-07T14:00:00Z | 32.5 |
| 8 | Hank | 29 | true | User | 852 Walnut St | Shelbyville | 67890 | 2024-05-08T15:00:00Z | 29.5 |
| 9 | Ivy | 27 | true | Admin,User | 963 Cherry St | Ogdenville | 54321 | 2024-05-09T16:00:00Z | 27.5 |
| 10 | Jack | 45 | false | Manager | 159 Spruce St | Springfield | 12345 | 2024-05-10T17:00:00Z | 45.5 |

`作成`アクションで上記を設定して、今後の動作を解説します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/7e3f32dd-8376-67ee-4175-a815f20bdfbc.png)

## データ操作の検証範囲
Power Queryで実現できている`テーブル`また`列`の操作を、可能な限り再現してみます。
テーマは下記のとおりです。

 1. **[フィルター（複数条件を含む）](https://qiita.com/DEmodoriGatsuO/items/f3416e181475d6dbc508#1-%E3%83%95%E3%82%A3%E3%83%AB%E3%82%BF%E3%83%BC)**
 1. **[列の選択](https://qiita.com/DEmodoriGatsuO/items/f3416e181475d6dbc508#2-%E5%88%97%E3%81%AE%E9%81%B8%E6%8A%9E)**
 1. **[列の分割](https://qiita.com/DEmodoriGatsuO/items/f3416e181475d6dbc508#3-%E5%88%97%E3%81%AE%E5%88%86%E5%89%B2)**
 1. **[ソート](https://qiita.com/DEmodoriGatsuO/items/f3416e181475d6dbc508#4-%E3%82%BD%E3%83%BC%E3%83%88)**
 1. **[重複の削除](https://qiita.com/DEmodoriGatsuO/items/f3416e181475d6dbc508#5-%E9%87%8D%E8%A4%87%E3%81%AE%E5%89%8A%E9%99%A4)**
 1. **[インデックスの付与](https://qiita.com/DEmodoriGatsuO/items/f3416e181475d6dbc508#6-%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AE%E4%BB%98%E4%B8%8E)**
 1. **[グループ化(むりやり)](https://qiita.com/DEmodoriGatsuO/items/f3416e181475d6dbc508#6-%E3%82%B0%E3%83%AB%E3%83%BC%E3%83%97%E5%8C%96)**


### 1. フィルター
[アレイのフィルター処理](https://learn.microsoft.com/ja-jp/power-automate/data-operations#use-the-filter-array-action)で完結します。
例えば`id`が5以上の場合は、

- `from` `@{body('ParseJSON_PracticeJSON')}`
- `Filter Query` `@greaterOrEquals(item()['id'],5)`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/face5969-f30d-45ad-8eb9-0fd4e0dcdcdd.png)

<details><summary>結果</summary>

```json:output
[
  {
    "id": 1,
    "name": "Alice",
    "age": 25,
    "isActive": true,
    "roles": [
      "Admin",
      "User"
    ],
    "address": {
      "street": "123 Main St",
      "city": "Springfield",
      "zip": "12345"
    },
    "lastLogin": "2024-05-01T08:00:00Z",
    "floatValue": 25.5
  },
  {
    "id": 2,
    "name": "Bob",
    "age": 30,
    "isActive": false,
    "roles": [
      "User"
    ],
    "address": {
      "street": "456 Elm St",
      "city": "Shelbyville",
      "zip": "67890"
    },
    "lastLogin": "2024-05-02T09:00:00Z",
    "floatValue": 30.5
  },
  {
    "id": 3,
    "name": "Charlie",
    "age": 35,
    "isActive": true,
    "roles": [
      "Admin",
      "Manager",
      "User"
    ],
    "address": {
      "street": "789 Oak St",
      "city": "Ogdenville",
      "zip": "54321"
    },
    "lastLogin": "2024-05-03T10:00:00Z",
    "floatValue": 35.5
  },
  {
    "id": 4,
    "name": "David",
    "age": 28,
    "isActive": false,
    "roles": [
      "User"
    ],
    "address": {
      "street": "321 Pine St",
      "city": "Springfield",
      "zip": "12345"
    },
    "lastLogin": "2024-05-04T11:00:00Z",
    "floatValue": 28.5
  },
  {
    "id": 5,
    "name": "Eve",
    "age": 22,
    "isActive": true,
    "roles": [
      "User"
    ],
    "address": {
      "street": "654 Maple St",
      "city": "Shelbyville",
      "zip": "67890"
    },
    "lastLogin": "2024-05-05T12:00:00Z",
    "floatValue": 22.5
  },
  {
    "id": 6,
    "name": "Frank",
    "age": 40,
    "isActive": true,
    "roles": [
      "Manager",
      "User"
    ],
    "address": {
      "street": "987 Birch St",
      "city": "Ogdenville",
      "zip": "54321"
    },
    "lastLogin": "2024-05-06T13:00:00Z",
    "floatValue": 40.5
  },
  {
    "id": 7,
    "name": "Grace",
    "age": 32,
    "isActive": false,
    "roles": [
      "Admin",
      "User"
    ],
    "address": {
      "street": "741 Cedar St",
      "city": "Springfield",
      "zip": "12345"
    },
    "lastLogin": "2024-05-07T14:00:00Z",
    "floatValue": 32.5
  },
  {
    "id": 8,
    "name": "Hank",
    "age": 29,
    "isActive": true,
    "roles": [
      "User"
    ],
    "address": {
      "street": "852 Walnut St",
      "city": "Shelbyville",
      "zip": "67890"
    },
    "lastLogin": "2024-05-08T15:00:00Z",
    "floatValue": 29.5
  },
  {
    "id": 9,
    "name": "Ivy",
    "age": 27,
    "isActive": true,
    "roles": [
      "Admin",
      "User"
    ],
    "address": {
      "street": "963 Cherry St",
      "city": "Ogdenville",
      "zip": "54321"
    },
    "lastLogin": "2024-05-09T16:00:00Z",
    "floatValue": 27.5
  },
  {
    "id": 10,
    "name": "Jack",
    "age": 45,
    "isActive": false,
    "roles": [
      "Manager"
    ],
    "address": {
      "street": "159 Spruce St",
      "city": "Springfield",
      "zip": "12345"
    },
    "lastLogin": "2024-05-10T17:00:00Z",
    "floatValue": 45.5
  }
]
```

</details>

#### 複数条件 - And条件

`詳細設定モード`から編集した場合、複数条件に対処できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/f70a3a04-032c-4326-c7f9-dd40a15d6008.png)

例えば`id`が5以上で、`age`が30以下としましょう。
その場合、設定は下記のようになります。

```plaintext:Filter Query
and(greaterOrEquals(item()['id'],5),lessOrEquals(item()['age'],30))
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/00d33fe2-f04a-fe80-00e8-52ad07d60b34.png)

<details><summary>結果</summary>

```json:output
[
  {
    "id": 5,
    "name": "Eve",
    "age": 22,
    "isActive": true,
    "roles": [
      "User"
    ],
    "address": {
      "street": "654 Maple St",
      "city": "Shelbyville",
      "zip": "67890"
    },
    "lastLogin": "2024-05-05T12:00:00Z",
    "floatValue": 22.5
  },
  {
    "id": 6,
    "name": "Frank",
    "age": 40,
    "isActive": true,
    "roles": [
      "Manager",
      "User"
    ],
    "address": {
      "street": "987 Birch St",
      "city": "Ogdenville",
      "zip": "54321"
    },
    "lastLogin": "2024-05-06T13:00:00Z",
    "floatValue": 40.5
  },
  {
    "id": 7,
    "name": "Grace",
    "age": 32,
    "isActive": false,
    "roles": [
      "Admin",
      "User"
    ],
    "address": {
      "street": "741 Cedar St",
      "city": "Springfield",
      "zip": "12345"
    },
    "lastLogin": "2024-05-07T14:00:00Z",
    "floatValue": 32.5
  },
  {
    "id": 8,
    "name": "Hank",
    "age": 29,
    "isActive": true,
    "roles": [
      "User"
    ],
    "address": {
      "street": "852 Walnut St",
      "city": "Shelbyville",
      "zip": "67890"
    },
    "lastLogin": "2024-05-08T15:00:00Z",
    "floatValue": 29.5
  },
  {
    "id": 9,
    "name": "Ivy",
    "age": 27,
    "isActive": true,
    "roles": [
      "Admin",
      "User"
    ],
    "address": {
      "street": "963 Cherry St",
      "city": "Ogdenville",
      "zip": "54321"
    },
    "lastLogin": "2024-05-09T16:00:00Z",
    "floatValue": 27.5
  },
  {
    "id": 10,
    "name": "Jack",
    "age": 45,
    "isActive": false,
    "roles": [
      "Manager"
    ],
    "address": {
      "street": "159 Spruce St",
      "city": "Springfield",
      "zip": "12345"
    },
    "lastLogin": "2024-05-10T17:00:00Z",
    "floatValue": 45.5
  }
]
```
</details>

### 2. 列の選択
列を限定したり、加工するためには、 **[選択(Select)](https://learn.microsoft.com/ja-jp/power-automate/data-operations#use-the-filter-array-action)** アクションが活躍します。

https://qiita.com/DEmodoriGatsuO/items/aabff4e30bba821c39b7

https://learn.microsoft.com/ja-jp/power-automate/data-operations#use-the-filter-array-action

初回、とっつきにくい印象もありますが**非常に強力な機能です。**
ぜひ習得されることをおススメします。

#### シンプルな列の選択と配列の結合

- `From` `@{body('ParseJSON_PracticeJSON')}`

```plaintext:Map
{
  "id": @{item()['id']},
  "name": @{item()['name']},
  "roles": @{join(item()['roles'],',')}
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/e4f3bfeb-815d-1e3b-9aab-d6e3fb5c1f02.png)

こちらにより
1. `id`、`name`の列に限定し
1. データ型が`array`の`roles`列を[join関数](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#join)で結合しています

https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#join

<details><summary>結果</summary>

```json:output
[
  {
    "id": 1,
    "name": "Alice",
    "roles": "Admin,User"
  },
  {
    "id": 2,
    "name": "Bob",
    "roles": "User"
  },
  {
    "id": 3,
    "name": "Charlie",
    "roles": "Admin,Manager,User"
  },
  {
    "id": 4,
    "name": "David",
    "roles": "User"
  },
  {
    "id": 5,
    "name": "Eve",
    "roles": "User"
  },
  {
    "id": 6,
    "name": "Frank",
    "roles": "Manager,User"
  },
  {
    "id": 7,
    "name": "Grace",
    "roles": "Admin,User"
  },
  {
    "id": 8,
    "name": "Hank",
    "roles": "User"
  },
  {
    "id": 9,
    "name": "Ivy",
    "roles": "Admin,User"
  },
  {
    "id": 10,
    "name": "Jack",
    "roles": "Manager"
  }
]
```
</details>

この選択は、`列を追加`したり、`データ型を変換`することにも有効です。

1. 値の置き換え
1. データ型変換
1. 書式変換

を試してみます。

#### 1. 値の置き換え
既存の列を選択して、`age`列の式を1.1倍に置き換えることができます。
`if`関数なども使えるので、関数の使い方によって、様々な値に変えることができます。

```plaintext:age列
mul(item()['age'],1.1)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/64edfe14-0187-2f02-ebd7-e374e6395c17.png)

#### 2. データ型変換
`age`列に`歳`という文字列を着けて、列ごと`String`型に変えましょう。

```plaintext:age列
concat(string(item()['age']),'歳')
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/2214a9a5-ebc4-888d-cf14-b9339b495d1f.png)

さくっと変換できますね

#### 3. 書式変換
`lastLogin`列が、日付文字列なので、`yyyy-MM-dd hh:mm:ss`に変換します。
[formatDateTime関数](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#formatDateTime)です。

https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#formatDateTime

```plaintext:lastLogin列
formatDateTime(item()['lastLogin'],'yyyy-MM-dd hh:mm:ss')
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/7bca1c80-2f7f-eec9-77fb-1e1353a93e22.png)

年や月、日付も取得できます。便利ですね。

#### 選択による加工の結果

<details><summary>1,2,3の結果</summary>

```json:output
[
  {
    "id": 1,
    "name": "Alice",
    "age": "25歳",
    "ageMul": 27.500000000000004,
    "ageString": "25歳",
    "lastLogin": "2024-05-01 08:00:00"
  },
  {
    "id": 2,
    "name": "Bob",
    "age": "30歳",
    "ageMul": 33,
    "ageString": "30歳",
    "lastLogin": "2024-05-02 09:00:00"
  },
  {
    "id": 3,
    "name": "Charlie",
    "age": "35歳",
    "ageMul": 38.5,
    "ageString": "35歳",
    "lastLogin": "2024-05-03 10:00:00"
  },
  {
    "id": 4,
    "name": "David",
    "age": "28歳",
    "ageMul": 30.800000000000004,
    "ageString": "28歳",
    "lastLogin": "2024-05-04 11:00:00"
  },
  {
    "id": 5,
    "name": "Eve",
    "age": "22歳",
    "ageMul": 24.200000000000003,
    "ageString": "22歳",
    "lastLogin": "2024-05-05 12:00:00"
  },
  {
    "id": 6,
    "name": "Frank",
    "age": "40歳",
    "ageMul": 44,
    "ageString": "40歳",
    "lastLogin": "2024-05-06 01:00:00"
  },
  {
    "id": 7,
    "name": "Grace",
    "age": "32歳",
    "ageMul": 35.2,
    "ageString": "32歳",
    "lastLogin": "2024-05-07 02:00:00"
  },
  {
    "id": 8,
    "name": "Hank",
    "age": "29歳",
    "ageMul": 31.900000000000002,
    "ageString": "29歳",
    "lastLogin": "2024-05-08 03:00:00"
  },
  {
    "id": 9,
    "name": "Ivy",
    "age": "27歳",
    "ageMul": 29.700000000000003,
    "ageString": "27歳",
    "lastLogin": "2024-05-09 04:00:00"
  },
  {
    "id": 10,
    "name": "Jack",
    "age": "45歳",
    "ageMul": 49.50000000000001,
    "ageString": "45歳",
    "lastLogin": "2024-05-10 05:00:00"
  }
]
```

</details>

### 3. 列の分割
列の分割も、**[選択(Select)](https://learn.microsoft.com/ja-jp/power-automate/data-operations#use-the-filter-array-action)** アクションの出番です。

`Apply to each`ではなく、`選択(Select)`を使うことで、高速で処理できます。

#### 配列から抽出する例
JSONのうち、`roles`列は、array型です。
中身をとって複数の列に分割します。

- `from` `@{body('ParseJSON_PracticeJSON')}`

```plaintext:Map
{
  "id": @{item()['id']},
  "name": @{item()['name']},
  "roles1": @{item()['roles']?[0]},
  "roles2": @{item()['roles']?[1]}
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/ca180865-5e3f-223d-470d-384f91860f23.png)


### 4. ソート
[sort関数](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#sort)を使います。
並べ替えに使用するキー列は **文字列** で設定することがポイント。

[作成アクション](https://learn.microsoft.com/ja-jp/power-automate/data-operations#use-the-compose-action)で、並び替えの結果を反映します。

```plaintext:入力
sort(body('ParseJSON_PracticeJSON'),'age')
```

上記は`age`列をもとに昇順で並び替えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/0b726adf-f12c-5e3d-54de-0efdedf38ad3.png)

https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#sort

<details><summary>結果</summary>

```json:output
[
  {
    "id": 5,
    "name": "Eve",
    "age": 22,
    "isActive": true,
    "roles": [
      "User"
    ],
    "address": {
      "street": "654 Maple St",
      "city": "Shelbyville",
      "zip": "67890"
    },
    "lastLogin": "2024-05-05T12:00:00Z",
    "floatValue": 22.5
  },
  {
    "id": 1,
    "name": "Alice",
    "age": 25,
    "isActive": true,
    "roles": [
      "Admin",
      "User"
    ],
    "address": {
      "street": "123 Main St",
      "city": "Springfield",
      "zip": "12345"
    },
    "lastLogin": "2024-05-01T08:00:00Z",
    "floatValue": 25.5
  },
  {
    "id": 9,
    "name": "Ivy",
    "age": 27,
    "isActive": true,
    "roles": [
      "Admin",
      "User"
    ],
    "address": {
      "street": "963 Cherry St",
      "city": "Ogdenville",
      "zip": "54321"
    },
    "lastLogin": "2024-05-09T16:00:00Z",
    "floatValue": 27.5
  },
  {
    "id": 4,
    "name": "David",
    "age": 28,
    "isActive": false,
    "roles": [
      "User"
    ],
    "address": {
      "street": "321 Pine St",
      "city": "Springfield",
      "zip": "12345"
    },
    "lastLogin": "2024-05-04T11:00:00Z",
    "floatValue": 28.5
  },
  {
    "id": 8,
    "name": "Hank",
    "age": 29,
    "isActive": true,
    "roles": [
      "User"
    ],
    "address": {
      "street": "852 Walnut St",
      "city": "Shelbyville",
      "zip": "67890"
    },
    "lastLogin": "2024-05-08T15:00:00Z",
    "floatValue": 29.5
  },
  {
    "id": 2,
    "name": "Bob",
    "age": 30,
    "isActive": false,
    "roles": [
      "User"
    ],
    "address": {
      "street": "456 Elm St",
      "city": "Shelbyville",
      "zip": "67890"
    },
    "lastLogin": "2024-05-02T09:00:00Z",
    "floatValue": 30.5
  },
  {
    "id": 7,
    "name": "Grace",
    "age": 32,
    "isActive": false,
    "roles": [
      "Admin",
      "User"
    ],
    "address": {
      "street": "741 Cedar St",
      "city": "Springfield",
      "zip": "12345"
    },
    "lastLogin": "2024-05-07T14:00:00Z",
    "floatValue": 32.5
  },
  {
    "id": 3,
    "name": "Charlie",
    "age": 35,
    "isActive": true,
    "roles": [
      "Admin",
      "Manager",
      "User"
    ],
    "address": {
      "street": "789 Oak St",
      "city": "Ogdenville",
      "zip": "54321"
    },
    "lastLogin": "2024-05-03T10:00:00Z",
    "floatValue": 35.5
  },
  {
    "id": 6,
    "name": "Frank",
    "age": 40,
    "isActive": true,
    "roles": [
      "Manager",
      "User"
    ],
    "address": {
      "street": "987 Birch St",
      "city": "Ogdenville",
      "zip": "54321"
    },
    "lastLogin": "2024-05-06T13:00:00Z",
    "floatValue": 40.5
  },
  {
    "id": 10,
    "name": "Jack",
    "age": 45,
    "isActive": false,
    "roles": [
      "Manager"
    ],
    "address": {
      "street": "159 Spruce St",
      "city": "Springfield",
      "zip": "12345"
    },
    "lastLogin": "2024-05-10T17:00:00Z",
    "floatValue": 45.5
  }
]
```
</details>



#### 降順にする
[sort関数](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#sort)を使った配列をもとに、[reverse関数](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#reverse)を使うことで、
**sortで指定したキー列を用いて並び替え**ができます。

```plaintext:入力
@{reverse(outputs('04ソート昇順'))}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/96acd96c-983d-32c8-09c9-1bf4672a5bdf.png)

https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#reverse

:::note warn
[reverse関数](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#reverse)単体では、並べ替えに使用するキーを指定できないようです
:::

<details><summary>結果</summary>

```json:output
[
  {
    "id": 10,
    "name": "Jack",
    "age": 45,
    "isActive": false,
    "roles": [
      "Manager"
    ],
    "address": {
      "street": "159 Spruce St",
      "city": "Springfield",
      "zip": "12345"
    },
    "lastLogin": "2024-05-10T17:00:00Z",
    "floatValue": 45.5
  },
  {
    "id": 6,
    "name": "Frank",
    "age": 40,
    "isActive": true,
    "roles": [
      "Manager",
      "User"
    ],
    "address": {
      "street": "987 Birch St",
      "city": "Ogdenville",
      "zip": "54321"
    },
    "lastLogin": "2024-05-06T13:00:00Z",
    "floatValue": 40.5
  },
  {
    "id": 3,
    "name": "Charlie",
    "age": 35,
    "isActive": true,
    "roles": [
      "Admin",
      "Manager",
      "User"
    ],
    "address": {
      "street": "789 Oak St",
      "city": "Ogdenville",
      "zip": "54321"
    },
    "lastLogin": "2024-05-03T10:00:00Z",
    "floatValue": 35.5
  },
  {
    "id": 7,
    "name": "Grace",
    "age": 32,
    "isActive": false,
    "roles": [
      "Admin",
      "User"
    ],
    "address": {
      "street": "741 Cedar St",
      "city": "Springfield",
      "zip": "12345"
    },
    "lastLogin": "2024-05-07T14:00:00Z",
    "floatValue": 32.5
  },
  {
    "id": 2,
    "name": "Bob",
    "age": 30,
    "isActive": false,
    "roles": [
      "User"
    ],
    "address": {
      "street": "456 Elm St",
      "city": "Shelbyville",
      "zip": "67890"
    },
    "lastLogin": "2024-05-02T09:00:00Z",
    "floatValue": 30.5
  },
  {
    "id": 8,
    "name": "Hank",
    "age": 29,
    "isActive": true,
    "roles": [
      "User"
    ],
    "address": {
      "street": "852 Walnut St",
      "city": "Shelbyville",
      "zip": "67890"
    },
    "lastLogin": "2024-05-08T15:00:00Z",
    "floatValue": 29.5
  },
  {
    "id": 4,
    "name": "David",
    "age": 28,
    "isActive": false,
    "roles": [
      "User"
    ],
    "address": {
      "street": "321 Pine St",
      "city": "Springfield",
      "zip": "12345"
    },
    "lastLogin": "2024-05-04T11:00:00Z",
    "floatValue": 28.5
  },
  {
    "id": 9,
    "name": "Ivy",
    "age": 27,
    "isActive": true,
    "roles": [
      "Admin",
      "User"
    ],
    "address": {
      "street": "963 Cherry St",
      "city": "Ogdenville",
      "zip": "54321"
    },
    "lastLogin": "2024-05-09T16:00:00Z",
    "floatValue": 27.5
  },
  {
    "id": 1,
    "name": "Alice",
    "age": 25,
    "isActive": true,
    "roles": [
      "Admin",
      "User"
    ],
    "address": {
      "street": "123 Main St",
      "city": "Springfield",
      "zip": "12345"
    },
    "lastLogin": "2024-05-01T08:00:00Z",
    "floatValue": 25.5
  },
  {
    "id": 5,
    "name": "Eve",
    "age": 22,
    "isActive": true,
    "roles": [
      "User"
    ],
    "address": {
      "street": "654 Maple St",
      "city": "Shelbyville",
      "zip": "67890"
    },
    "lastLogin": "2024-05-05T12:00:00Z",
    "floatValue": 22.5
  }
]
```

</details>


### 5. 重複の削除
重複を削除するために、まずは重複を作成します。
`age`列から、30歳未満（`other`）と30歳以上（`under30`）で分類します。
使うのは、やはり選択アクションです。

- `From` `@{body('ParseJSON_PracticeJSON')}`

```Map
{
  "ages": @{if(greaterOrEquals(item()?['age'],30),'other','under30')}
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/0b41cf83-90d5-56eb-fdff-ca4a48280c41.png)

こちらを実行すると、分類された結果が返ってきます。

```json:分類された結果
[
  {
    "ages": "under30"
  },
  {
    "ages": "other"
  },
  {
    "ages": "other"
  },
  {
    "ages": "under30"
  },
  {
    "ages": "under30"
  },
  {
    "ages": "other"
  },
  {
    "ages": "other"
  },
  {
    "ages": "under30"
  },
  {
    "ages": "under30"
  },
  {
    "ages": "other"
  }
]
```

こちらを[union関数](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#union)を用いて、重複を省きます。

作成アクションで下記の関数を実行します。

```plaintext:入力
union(body('05重複を事前に作成'),body('05重複を事前に作成'))
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/aa6cb207-e8e2-6e0d-2994-0daeba5bb49c.png)

`同じ値をunion???`と混乱しそうですが、**和集合** になっています。
比較元と比較先のリストの構造が一致していると、データ双方にあるデータを取得し、重複を排除します。

```
[
  {
    "ages": "under30"
  },
  {
    "ages": "other"
  }
]
```

https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#union

**■ 和集合のイメージ**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/1c6739c7-a2bc-7f64-4ab7-d3b408a48c00.png)

### 6. インデックスの付与
今度はJSON配列入力に、インデックス列を設ける方法を解説します。

1. 作成アクションから[range関数](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#range)で配列の要素数に合わせて、インデックス列を設けて
1. 選択アクションで結合します

#### 1. 作成アクション [range関数](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#range)

```plaintext:入力
range(0, length(body('ParseJSON_PracticeJSON')))
```

JSON配列入力の要素数をlength関数で算出しています。

```json:range関数の結果
[
  0,
  1,
  2,
  3,
  4,
  5,
  6,
  7,
  8,
  9
]
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/2e25a736-3ee2-6c94-2a0c-9ef7428a20fa.png)

https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#range

#### 2. 選択アクションで結合
`id`列と`name`列を残し、(1)で作成した連番と結合します。

- `From` `@{outputs('06インデックスの付与の事前準備')}`

```Map
{
  "index": @{item()},
  "id": @{body('ParseJSON_PracticeJSON')[item()]?['id']},
  "name": @{body('ParseJSON_PracticeJSON')[item()]?['name']}
}
```

`index`である`item()`が、JSON配列入力の添え字にもなっています。
`index`が0始まりになっていますが、そこはお好みで修正してください。

**このテクニックは今後出番がありそう！**

<details><summary>結果</summary>

```json:Output
[
  {
    "index": 0,
    "id": 1,
    "name": "Alice"
  },
  {
    "index": 1,
    "id": 2,
    "name": "Bob"
  },
  {
    "index": 2,
    "id": 3,
    "name": "Charlie"
  },
  {
    "index": 3,
    "id": 4,
    "name": "David"
  },
  {
    "index": 4,
    "id": 5,
    "name": "Eve"
  },
  {
    "index": 5,
    "id": 6,
    "name": "Frank"
  },
  {
    "index": 6,
    "id": 7,
    "name": "Grace"
  },
  {
    "index": 7,
    "id": 8,
    "name": "Hank"
  },
  {
    "index": 8,
    "id": 9,
    "name": "Ivy"
  },
  {
    "index": 9,
    "id": 10,
    "name": "Jack"
  }
]
```
</details>


### 6. グループ化
最後に`グループ化`を解説します。
先に申し上げますと、かなり難しかったです。

■ 順序
1. グループ化の結果を格納する配列変数を準備（変数の初期化）
1. グループ化のためのユニークな値の配列を作成
1. 重複を削除
1. (3)で作成した重複のないリストから繰り返し処理
    1. アレイのフィルター処理で、ユニーク値に対する絞り込みを実施
    1. 配列に格納する結果を作成
    1. 配列変数に追加

という手順になっています。

#### 1. グループ化の結果を格納する配列変数を準備（変数の初期化）
シンプルな変数の初期化です。

```plaintext:Value
[]
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/1bc2cde8-0bb9-71e1-242b-6bcc93d59383.png)

#### 2. グループ化のためのユニークな値の配列を作成
[重複の削除]()と同じアプローチをとります。
`age`列の値から分類します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/8d3d1540-315f-ffc7-5bd4-40fba1728f72.png)

※ 式は[重複の削除](https://qiita.com/DEmodoriGatsuO/items/f3416e181475d6dbc508#5-%E9%87%8D%E8%A4%87%E3%81%AE%E5%89%8A%E9%99%A4)と同様です。

#### 3. 重複を削除
同上

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/1167da77-b4f6-c650-75e0-a570f2512b8c.png)

※ 式は[重複の削除](https://qiita.com/DEmodoriGatsuO/items/f3416e181475d6dbc508#5-%E9%87%8D%E8%A4%87%E3%81%AE%E5%89%8A%E9%99%A4)と同様です。

#### 4. (3)で作成した重複のないリストから繰り返し処理
ここで`For each`もとい`Apply to each`を使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/6b51bf30-1fea-6120-89e5-0fd68fc15b89.png)

繰り返しのもととなる配列は、(3)で作成した重複のないリスト`@{outputs('07グループ化_ユニークキーの作成2')}`です。

##### 1. アレイのフィルター処理で、ユニーク値に対する絞り込みを実施
ここの`アレイのフィルター処理`がポイントです。
(2)で作成した重複削除前の配列を`From`に設定し、ユニーク値による絞り込みを実施します。

- `From` `@{body('07グループ化_ユニークキーの作成1')}`

```Map
@equals(@{item()},@{items('For_each')})
```

- アレイのフィルター処理に対応する値 : `item()`と、
- For eachに対応する : `items('For_each')`

上記の比較です。頭がこんがらがりますね。
こんなことをやるには向いていないというお達しでしょう。

##### 2. 配列に格納する結果を作成
作成アクションで、配列に格納するオブジェクトを設定します。
グループ化による行数のカウントを実現しています。

```json:配列に格納するオブジェクト
{
  "ages": "@{items('For_each')?['ages']}",
  "count": @{length(body('アレイのフィルター処理'))}
}
```

##### 3. 配列変数に追加
前述のオブジェクトを配列に格納します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/90f7fb3c-0ea1-9ece-c170-1a0b513cc89a.png)

```json:グループ化した結果（行数のカウント）
[
  {
    "ages": "under30",
    "count": 5
  },
  {
    "ages": "other",
    "count": 5
  }
]
```

# おわりに
軽い気持ちで書き始めましたが、非常に時間がかかる検証でした・・・。
テクニックにより、データ調理の幅が広がりそうですが、ロジックを考えるのが大変ですね💦

知恵熱を出しそうです。
間違いあればご指摘ください。