【IRIS】【JSON】%DynamicArray

今回は、IRISでJSON的な操作が可能になる%DynamicArrayについて解説します。

※この記事は下記の方向けになります。
  • %DynamicArrayの操作を行ったことがない方
  • ObjectScriptで外部APIとの連携を行いたい方
  • データを格納する箱的な位置づけを探している方

はじめに

%DynamicArrayは、JSONのような動的なデータ構造を扱うためのクラスです。
JSON形式のデータを柔軟に生成・操作・変換したり、外部APIとの連携でJSONデータを扱い場合にも便利です。

サンプルは全てIRIS 2023.1.2.450.0で作成しています。

今回はJSON風の配列を扱うクラス、%DynamicArrayについて解説します。
基本的な動作に関しては%DynamicObjectと同じため、共通している箇所に関しては下記記事を参照してください。

基本操作

オブジェクト生成

ClassMethod sample()
{
	s name = "藤原道長"
	s json = [
		(name),
		"男",
		{
			"長男": "藤原頼通",
			"次男": "藤原頼宗"
		},
		"関白",
		(2*5)
	]
	
	s json."5" = "add!!" // 配列の番号を直接指定する
	
	d json.%Push(1,"boolean").%Push("","null").%ToJSON()
}

%DynamicArrayは、JSONのオブジェクトを模しているので、ObjectScriptとは異なり配列の番号は0から始まります。

そのため、6番目に挿入したい場合は、「s json.5 = “add!!」になります。
0から始まり6番目である「5」に挿入ですね。

%Push(value, type)」は、%DynamicObjectの%Setと同様に、型を変換して配列に追加る事が可能です。
 →今回は、7番目に「1」、8番目に「“”」を追加しました。

【関数の実行結果】
[
 ”藤原道長”,
 ”男”,
 {“長男”:”藤原頼通”,”次男”:”藤原頼宗”},
 ”関白”,
 10,
 ”add!!“,
 true,
 null
]

%Pushの型(type)は%Setのの型と同様の為、割愛します。

空の値

配列のキーを直接指定して値を格納する事ができるのであれば、格納されていない配列位置はどうなっているのでしょうか。

ClassMethod sample()
{
	s json = []	
	s json."5" = "add!!" // 空の配列に対し、5番目に格納する
	
	w json.%ToJSON(),!!
	
	s iter = json.%GetIterator()
	while iter.%GetNext(.prop, .val, .type) {
		w "prop:",prop,", val:",val,", type:",type,!
	}
	
	w !,"---------------------",!
	w "配列数:",json.%Size(),!
	w "空の型:",json.%GetTypeOf("0")
}

【関数の実行結果】
[null,null,null,null,null,”add!!”]

prop:5, val:add!!, type:string
———————–
配列数:6
空の型:unassigned

ここで分かることは、下記になります。

  • 配列の数は6個
  • 1~5個までは値が入っておらず、空の型は「unassigned
  • イテレータを使用すると、格納されたデータのみ(今回は6番目)取得できる

一先ず配列分回す

ClassMethod sample()
{
	s json = []	
	s json."3" = "add!!"
	
	f pos=0:1:json.%Size()-1 {
		w json.%Get(pos,"null!"),!
	}
}

【関数の実行結果】
null!
null!
null!
add!!

値が格納されていなくても、配列分ループしたいときはforループを使えばよいと思います。
値の中身は毎回チェックする必要があります。

格納されている分だけ配列を回す

ClassMethod sample()
{
	s json = []	
	s json."5" = "add!!"
	
	s iter = json.%GetIterator()
	while iter.%GetNext(.prop, .val, .type) {
		w "prop:",prop,", val:",val,", type:",type,!
	}	
}

イテレータを使用した取得方法になります。

実装例

%DynamicArrayの機能を使った下記実装例を2点確認したいと思います。

  • Queue機能
  • Undo/Redo機能

Queue機能の実装

Queue機能は、通信処理でよく見ますね。

ClassMethod sample()
{
	s json = [1,2,3,4,5]
	f pos=6:1:10 {
        d json.%Push(pos)
		w json.%Remove(0),!
	}
	d json.%ToJSON()
}

%Push」と「%Remove」の組み合わせは、キュー(Queue)機能(いわゆる後入れ/先出し)を実装する際に便利な組み合わせです。

【関数の実行結果】
1
2
3
4
5
[6,7,8,9,10]

Undo/Redo機能の実装

Undo/Redo機能は、お絵かきソフトや将棋・オセロ等のゲームでよく見ますね。

ClassMethod sample()
{
	s json = [1,2,3,4,5]
	f pos=6:1:10 {
		d json.%Push(pos)
		w json.%Pop(),!
	}
	d json.%ToJSON()
}

%Push」と「%Pop」を組み合わせると、Undo/Redo機能(いわゆる後入れ/後出し)を実装するのに便利な組み合わせです。

【関数の実行結果】
6
7
8
9
10
[1,2,3,4,5]

%Listとのパフォーマンス比較

%DynamicArrayの機能と比較的近い立場にあるのが、%Listになると思います。

両者は、文字列(%List)とオブジェクト(%DynamicArray)なので、立ち位置が根本から異なりますが、順番に値を確保していく点は共通しています。

似ている様で全く立ち位置が異なりますが、今後実装を判断する基準としたいため、パフォーマンスの比較を行ってみたいと思います。

処理速度を比較するため、下記関数を用意してみました。

ClassMethod check(cnt As %Integer)
{
	s list = ""
	s start = $zh
	f pos=1:1:cnt {
		s $li(list, *+1)=pos
	}
	w !,"$list:",$zh - start
	
	
	s json = []
	s start = $zh
	f pos=1:1:cnt {
		d json.%Push(pos)
	}
	w !,"Array:",$zh - start
}
件数50件100件300件1,000件5,000件
$List0.0000640.0001270.0006480.0073410.178427
Array0.0001430.0003370.0006960.0022560.02038

%Listに100も200も詰め込むことがイレギュラーだとは思いますが、約300件を境に%Listと%DynamicArrayの処理速度が逆転するようです。

文字列である%List型は、やはり大量データには向いていないですね。

では、データの取り出しに関してはどうでしょうか。
下記関数を用意して計測を行いました。

ClassMethod check(cnt As %Integer)
{
	s list = ""
	f pos=1:1:cnt s $li(list, *+1)=pos
	
	s start = $zh
	s ptr=0
	while($listNext(list, ptr, val)){ }
	w !,"$list:",$zh - start
	
	
	s json = []
	f pos=1:1:cnt d json.%Push(pos)
	
	s start = $zh
	s iter = json.%GetIterator()
	while iter.%GetNext(, .val) {}
	w !,"Array:",$zh - start
}
件数50件100件1,000件5,000件
$List.0000110.0000130.000120.000353
Array0.0002580.0008490.0044660.02124

項目の取り出しに関しては、件数が増えれば増えるほど%Listが早く、%DynamicArrayの差が広がります。
わずかな差ではありますが、%DynamicArrayは遅いですね。

それよりも予想以上に%Listが優秀ですね。ビックリします。
順に値を取りに行く$ListNextの性能が高いのでしょう。

おわりに

いかがだったでしょうか。

本記事では、その基本的な使い方や特性、簡単な利用例について解説しました。

%DynamicArrayは、柔軟性と操作性に優れたデータ構造であり、従来の配列やグローバル変数と比べて、特定のシナリオで効率的なデータ操作を可能にします。

特に、JSON形式との親和性が高いため、外部APIやモダンなアプリケーションとの連携においても大きな力を発揮します。

このデータ構造を活用することで、より簡潔で直感的なコードを書けるだけでなく、アプリケーション全体の保守性や拡張性を向上させることができます。

今後も%DynamicArrayを適切に活用し、開発効率を高めていきたいですね!