Kuina-chan

くいなちゃん2018年10月19日


プログラミング言語Kuin」の逆引き辞典3、リスト型とスタック型とキュー型と辞書型の扱い方についてです。

目次

リスト型を扱う

「リスト」とは、配列と同様、同じ型の複数の変数をまとめて扱える型ですが、配列に比べて要素の追加、削除、挿入が高速に行えるため、動的に要素数が変わる場合に効率的な型です。
一方、要素番号を指定してアクセスする処理はリストよりも配列のほうが速く、要素数が頻繁に変わらない多くのケースでは配列のほうが効率的です。

リストを作成する

Kuinでのリストは「list<型名>」と書くことで、その型の値が複数集まったリストを表すことができます(リスト)。
func main()
  var items: list<int>
  do items :: #list<int>
  do items.add(3)
  do items.add(5)
end func
リスト
2行目のように「list<int>」とすると、int型のリストになります。
3行目のように「#list<型名>」と書くことで、リストのインスタンスが生成されます。
4~5行目のように「.add」メソッドを使うことで、リストの末尾に要素が追加できます。 このプログラムの場合、先頭から順に「3」「5」の値が格納されます。

リストの要素数を得る

リストの要素数は要素数演算子「^」で得ることができます(リストの要素数)。
func main()
  var items: list<int> :: #list<int>
  do items.add(3)
  do items.add(5)
  var num: int :: ^items {2}
end func
リストの要素数

リストの要素を順番に辿る

リストの要素には、リストが持つポインタを使ってアクセスします。 リストの要素を順番に辿るには、まずポインタを先頭に設定してから、終端に辿り着くまで1つずつ進めます(リストの走査)。
func main()
  var items: list<int> :: #list<int>
  do items.add(3)
  do items.add(5)
  do items.head() {ポインタを先頭に設定}
  while(!items.term()) {ポインタが終端を超えていなければ繰り返し}
    var item: int :: items.get() {ポインタの位置の要素を取得}
    do items.next() {ポインタを末尾へ進める}
  end while
end func
リストの走査
このプログラムではwhileの中が計2回実行され、変数itemには1回目には「3」、2回目には「5」が入っています。
リストの末尾から先頭に向かって逆順に辿るにはリストの逆順の走査のように書きます。
func main()
  var items: list<int> :: #list<int>
  do items.add(3)
  do items.add(5)
  do items.tail() {ポインタを末尾に設定}
  while(!items.term()) {ポインタが終端を超えていなければ繰り返し}
    var item: int :: items.get() {ポインタの位置の要素を取得}
    do items.prev() {ポインタを先頭へ進める}
  end while
end func
リストの逆順の走査

リストの要素を削除する

リストの要素を削除するには「.del」メソッドを使います。 「.del」メソッドを呼び出すと、ポインタの位置の要素が削除され、ポインタは次の要素を指すようになります(リストの要素の削除)。
func main()
  var items: list<int> :: #list<int>
  do items.add(3)
  do items.add(4)
  do items.add(5)
  do items.head()
  while(!items.term())
    var item: int :: items.get()
    if(item = 4)
      do items.del() {ポインタの位置の要素を削除して末尾へ進める}
    else
      do items.next()
    end if
  end while
end func
リストの要素の削除
実行すると、リストの先頭から「3」「4」「5」の要素が入っていたのが、「4」が削除され「3」「5」だけになります。
ポインタをその位置の要素を指すようにしたまま、その次の要素を削除するには「.delNext」メソッドを使います(リストの次の要素を削除)。
func main()
  var items: list<int> :: #list<int>
  do items.add(3)
  do items.add(4)
  do items.add(5)
  do items.head()
  do items.delNext()
end func
リストの次の要素を削除
実行すると「4」が削除され、リストの先頭から順に「3」「5」となります。

リストのポインタの位置に要素を挿入する

リストのポインタの位置に要素を挿入するには「.ins」メソッドを使います。 「.ins」メソッドを使うと、ポインタをその位置の要素を指すようにしたまま、その前に要素を挿入します(リストの要素の挿入)。
func main()
  var items: list<int> :: #list<int>
  do items.add(3)
  do items.add(5)
  do items.head()
  do items.next()
  do items.ins(4)
end func
リストの要素の挿入
実行すると、最終的にリストの先頭から順に「3」「4」「5」となります。

リストを配列に変換する

リストを配列に変換するには「.toArray」メソッドを使います(リストの配列化)。
func main()
  var items: list<int> :: #list<int>
  do items.add(3)
  do items.add(5)
  var array: []int :: items.toArray() {[3, 5]}
end func
リストの配列化

スタック型やキュー型を扱う

「スタック」は後に追加した要素から先に取り出されるデータ構造の型で、「キュー」は追加した順に要素が取り出されるデータ構造の型です。

スタックやキューを作成する

Kuinでスタックを表すには「stack<型名>」と書き、キューを表すには「queue<型名>」と書きます(スタックとキュー)。
func main()
  var stackItems: stack<int>
  var queueItems: queue<int>
  do stackItems :: #stack<int>
  do queueItems :: #queue<int>
  do stackItems.add(3)
  do queueItems.add(3)
end func
スタックとキュー
2~3行目のように「stack<int>」「queue<int>」とすると、int型のスタックやキューになります。
4~5行目のように「#stack<型名>」「#queue<型名>」と書くことで、スタックやキューのインスタンスが生成されます。
6~7行目のように「.add」メソッドを使うことで、スタックやキューに要素が追加できます。

スタックやキューの要素数を得る

スタックやキューの要素数は要素数演算子「^」で得ることができます(スタックやキューの要素数)。
func main()
  var stackItems: stack<int> :: #stack<int>
  var queueItems: queue<int> :: #queue<int>
  do stackItems.add(3)
  do queueItems.add(3)
  var stackNum: int :: ^stackItems {1}
  var queueNum: int :: ^queueItems {1}
end func
スタックやキューの要素数
スタックやキューが空かどうかを判定する場合には、「^」演算子を使って結果が0かどうかを調べます。

スタックやキューから要素を取得して削除する

スタックやキューから要素を取得するには「.get」メソッドを使います。 取得した要素はスタックやキューから削除されます(スタックやキューの要素の取得)。
func main()
  var stackItems: stack<int> :: #stack<int>
  var queueItems: queue<int> :: #queue<int>
  do stackItems.add(1)
  do stackItems.add(2)
  do queueItems.add(1)
  do queueItems.add(2)
  var item: int
  do item :: stackItems.get() {2}
  do item :: stackItems.get() {1}
  do item :: queueItems.get() {1}
  do item :: queueItems.get() {2}
end func
スタックやキューの要素の取得

スタックやキューから要素を削除せずに取得する

スタックやキューから要素を削除せずに取得するには「.peek」メソッドを使います(スタックやキューの要素を削除せずに取得)。
func main()
  var stackItems: stack<int> :: #stack<int>
  var queueItems: queue<int> :: #queue<int>
  do stackItems.add(1)
  do stackItems.add(2)
  do queueItems.add(1)
  do queueItems.add(2)
  var item: int
  do item :: stackItems.peek() {2}
  do item :: stackItems.peek() {2}
  do item :: queueItems.peek() {1}
  do item :: queueItems.peek() {1}
end func
スタックやキューの要素を削除せずに取得

辞書型を扱う

「辞書」はキーと値のペアを複数持ち、キーから値が高速に検索できるデータ構造の型です。

辞書を作成する

Kuinで辞書を表すには「dict<キーの型名, 値の型名>」と書きます(辞書)。
func main()
  var items: dict<[]char, int>
  do items :: #dict<[]char, int>
  do items.add("one", 1)
  do items.add("two", 2)
  do items.add("three", 3)
end func
辞書
2行目のように「dict<[]char, int>」とすると、キーが[]char型、値がint型の辞書になります。
3行目のように「#dict<キーの型名, 値の型名>」と書くことで、辞書のインスタンスが生成されます。
4行目のように「.add」メソッドを使うことで、辞書に要素が追加できます。

辞書の要素数を得る

辞書の要素数は要素数演算子「^」で得ることができます(辞書の要素数)。
func main()
  var items: dict<[]char, int> :: #dict<[]char, int>
  do items.add("one", 1)
  do items.add("two", 2)
  do items.add("three", 3)
  var num: int :: ^items {3}
end func
辞書の要素数

辞書から要素を取得する

辞書から要素を取得するには「.get」メソッドを使います(辞書の要素の取得)。
func main()
  var items: dict<[]char, int> :: #dict<[]char, int>
  do items.add("one", 1)
  do items.add("two", 2)
  do items.add("three", 3)
  var item: int :: items.get("two") {2}
end func
辞書の要素の取得
辞書にキーが見つからなければデフォルト値(int型の場合は0)が返ります。

辞書に要素が存在するかを判定する

辞書に要素が存在するかを判定するには「.exist」メソッドを使います(辞書の要素の存在の判定)。
func main()
  var items: dict<[]char, int> :: #dict<[]char, int>
  do items.add("one", 1)
  do items.add("two", 2)
  do items.add("three", 3)
  var existence: bool
  do existence :: items.exist("two") {true}
  do existence :: items.exist("five") {false}
end func
辞書の要素の存在の判定

辞書の全要素を順番に処理する

辞書に存在する全要素を順に処理するには「.forEach」メソッドを使います。 コールバック関数を渡すと、各要素に対してその関数が呼ばれる流れです(辞書の走査)。
func main()
  var items: dict<[]char, int> :: #dict<[]char, int>
  do items.add("one", 1)
  do items.add("two", 2)
  do items.add("three", 3)
  
  var str: lib@Str :: #lib@Str {文字列をラップしたクラス}
  do str.value :: "" {空文字列を設定しておく}
  var completed: bool :: items.forEach(callback, str) {true}
  
  func callback(key: []char, value: int, data: lib@Str): bool
    do data.value :~ "\{key}=\{value}." {各要素に対して文字列を追加する}
    ret true {継続する場合はtrue、中止する場合はfalseを返す}
  end func
end func
辞書の要素の存在の判定
9行目で「.forEach」メソッドを呼び出し、第1引数のコールバック関数にcallback関数を渡しています。 callback関数は11~14行目で定義しています。
「.forEach」の第2引数にはコールバック関数に渡すための任意のデータが指定できます。 ただしクラスでなければなりません。 今回は文字列型を渡したいのですが、文字列型はクラスではないため、文字列型をラップした「lib@Str」クラスを使っています。
コールバック関数が呼び出されるときの要素の順番は、キーを昇順に並べたときの順番です。 「"one"」「"two"」「"three"」を昇順(辞書順)に並べると「"one"」「"three"」「"two"」になるため、最終的に出来上がる「str.value」の値は「"one=1.three=3.two=2."」になります。
コールバック関数の戻り値をfalseにすると、「.forEach」の処理をそこで終わらせることができます。 終わらせた場合には「.forEach」メソッドの戻り値もfalseになり、最後まで処理した場合には戻り値はtrueになります。

辞書を配列に変換する

辞書を配列に変換するには「.toArrayKey」や「.toArrayValue」メソッドを使います(辞書の配列化)。
func main()
  var items: dict<[]char, int> :: #dict<[]char, int>
  do items.add("one", 1)
  do items.add("two", 2)
  do items.add("three", 3)
  var keys: [][]char :: items.toArrayKey() {["one", "three", "two"]}
  var values: []int :: items.toArrayValue() {[1, 3, 2]}
end func
辞書の配列化
配列化するときの要素の順番は、キーを昇順に並べたときの順番です。
1539959389jaf