【UiPath】行を指定して、列方向の並び替えをする

## 皆もすなるQiitaといふものを、儂もしてみむとてするなり。

と言う訳で、こん＊＊は！はなっち！です。

## 【初めに】 ##
色んな市民開発者の方と接していると、普段私が開発しているロボット仕様では考えつかない仕様で困っている話を聞く事があります。

今回は、 **DataTableの並び替え**に関してのお話。

## 【要望】 ##
　UiPathには、**「データテーブルを並び替え」アクティビティ**があって、これは
1. **列**を指定して
1. その値を評価して
1. **行方向**に並び替えをする

と言うのは知っている。

これを、業務要件で、
1. **行**を指定して
1. その値を評価して
1. **列方向**に並び替えをする

と言うをやりたい。

## 【はなっち！がポンと思いついた事】 ##
**行と列を入れ替えて**から、**「データテーブルを並び替え」アクティビティ**を使って並び替えをした後に、また**行と列を入れ替えて**元のレイアウトにしてあげればいいのでは？

[**はなっち！のDataTableアクティビティ**](https://cloud.uipath.com/hajime/marketplace_/listings/datatable?searchId=16ca5f3a-da1d-46c6-bd64-a78e7bd1755c)

ってカスタムアクティビティの中に、**「行列を入れ替える」アクティビティ**もあるんでと思った訳です。

## それが最適解なのかい？ ##
いや、何か**他に出来る方法**があるのではないか！？と、契約満了して灰色になった自分に**喝**！！

今回は、その**他に出来る方法**のご紹介です。
- - - 
## １）もう一度冷静に考えてみよう！
・**列方向への並び替え**は、**「列のレイアウト変更」** に他ならない。
・その **「列のレイアウト変更」** の **「列の順番」** を如何に決定するかは、指定された行の値を並び替える事で実現できる。
・ならば **指定された行の値と、その列の位置を別の方法で管理** してあげれば実現できるのではないか？

## ２）ロジックダイアグラム
### 2-1 指定された行の値と、その列の位置を別の方法で管理
ここでは、Dictionary(Of String, List(Of Int32))型の変数を用意し、
- Dictionary.Keyに、指定された行の値を指定
- Dictionary.Valueに、その列位置を格納（複数存在ｽする）

する。

**〔DataTable型の例〕** 
| Col1(0) | Col2(1) | Col3(2) | Col4(3) |
|:-:|:-:|:-:|:-:|
|値0|値1|値2|値3|
|キーA|キーC|キーB|キーA|
|値0|値1|値2|値3|

**〔Dictionary(Of String, List(Of Int32))の格納例〕**
|Of String|List(Of Int32)|
|:-:|:-:|
|キーA|0,3   |
|キーC|1   |
|キーB|2   |

### 2-2 そのDictionaryのキーを並び替える
**〔Dictionary(Of String, List(Of Int32))の格納例〕**
|Of String|List(Of Int32)|
|:-:|:-:|
|キーA|0,3   |
|キーB|2   |
|キーC|1   |

### 2-3 並び替えらえたDictionaryのValueの順に、列を追加していく
**〔DataTable型の元〕** 
| Col1(0) | Col2(1) | Col3(2) | Col4(3) |
|:-:|:-:|:-:|:-:|
|値0|値1|値2|値3|
|キーA|キーC|キーB|キーA|
|値0|値1|値2|値3|

**〔Dictionary型を順に評価し、更にDictionary型のValue(List(Of Int32))を順に評価し、DataTable型の先に、DataTable型の元の列情報を追加していく〕** 
キーAの1つ目...0列目
キーAの2つ目...3列目
キーBの1つ目...2列目
キーCの1つ目...1列目

**〔DataTable型の先〕** 
| Col1(0) | Col4(1) | Col3(2) | Col1(3) |
|:-:|:-:|:-:|:-:|

### 2-4 DataTable型の先へ、DataTable型の元の情報を「マージ」する。
**〔DataTable型の元〕** 
| Col1(0) | Col2(1) | Col3(2) | Col4(3) |
|:-:|:-:|:-:|:-:|
|値0|値1|値2|値3|
|キーA|キーC|キーB|キーA|
|値0|値1|値2|値3|

**「データテーブルをマージ」アクティビティ** を使用

**〔DataTable型の先〕** 
| Col1(0) | Col4(1) | Col3(2) | Col1(3) |
|:-:|:-:|:-:|:-:|
|値0|値3|値2|値1|
|キーA|キーA|キーB|キーC|
|値0|値3|値2|値1|

完成！

- - - 
## ３）実際
### 3-1 引数
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/871351bc-21c4-94fd-e7fe-007c9b9eda0a.png)
対象とするDataTableと、評価させる行位置を配列で指定と、並び替えた後のDataTableを指定する。

### 3-2 全体シーケンス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/0056a7b9-7f82-8c37-25b5-590b569d2aa9.png)

### 3-2-1 並び替え キー構成 シーケンス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/b2fe4ecd-c08b-2a64-f2e2-4be731fc0a83.png)

ここでは、対象とするDataTableの列方向へ、繰り返し、指定された行の値をキーを設定し、更にそのキーを評価し、列番号を格納します。

### 3-2-1-1 ColumnKey 設定 シーケンス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/d6df7716-9312-d20e-0109-b101f6297b47.png)

ここでは、指定された行（複数可能としている）を、タブ記号で連結し、それをキーとするようにしている。

### 3-2-1-2 ColumnKey 評価 シーケンス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/ba355f94-df58-97da-ad5c-a545228e4e17.png)
ここでは、Dictionary(Of String, List(Of Int32))に対して、先に設定したキーが既に存在しているかを評価する。
- 存在していなければ、一時的な変数(List(Of Int32))を初期化し、その時の行位置を格納する。
- 存在していれば、Value値を一時的な変数に代入し、そこにその時の行位置を格納する。

先に設定したキーに対して、先の一時的な変数を代入する。

※この時点で、「2-1 指定された行の値と、その列の位置を別の方法で管理」のDictionaryが作成される。

### 3-3-1 並び替え シーケンス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/11521234-cd5e-696e-043b-98a8127ebc95.png)
ここで、指定された行の値と、その値の列情報が格納されたDictionaryを並び替え、その情報から、新しいDataTableのレイアウトを作成し、データをマージする。

### 3-3-1-1 辞書 並び替え 代入
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/0fc1d996-a223-7ed3-a6c5-4dd63473cf2e.png)
単なる代入だが、「保存する値」側で、LINQを使ったSORTを実施している。

```
ColumnSortDictionary _
	.OrderBy(Function(kv) kv.Key) _
	.ToDictionary( _
		Function(kv) kv.Key, _
		Function(kv) kv.Value
	)
 ```

### 3-3-1-2 SortedDataTable 生成 シーケンス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/236638fc-7363-ca21-0ad0-d1bb3b86d79d.png)
- 「並び替えしたDataTable」領域の初期化を行い、最初の「繰り返し」アクティビティで、Dictionary全体を繰り返し、その配下の「繰り返し」アクティビティで、DictionaryのValue(List(Of Int32))を繰返す。
- そのValueの一つの要素が、「対象とするDataTable」の列位置が格納されているので、一時的な列変数を用意し、そこに、列名、列属性、最大長、Null可否、ユニーク値、省略時の値を設定する。
- その一時的な列変数を基に、「並び替えた後のDataTable」に列を追加する。

### 3-3-1-3 データ テーブルをマージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/36f0383c-7d3a-ef8f-3090-27ea3585f30d.png)
ここで「対象とするDataTable」から、データが空である「並び替えた後のDataTable」へマージする。
**「データテーブルをマージ」アクティビティ** は、

:::note
「対象とするDataTable」の列名が、受け側である「並び替えた後のDataTable」に存在すれば、その位置にデータをマージする
:::
ので、レイアウト変更、すなわち指定行での列方向への並び替えが行える。


- - - 
##おわりに
いかがでした？

今回も読んでいただきありがとうございました！
是非UiPathでのロボ開発の一助になればと思っています。

ありがとうございました！