1. ホーム
  2. スクリプト・コラム
  3. ルア

Luaチュートリアル(7)。データ構造の説明

2022-02-13 21:37:52

Luaのテーブルは単純なデータ構造ではなく、他のデータ構造の基礎として使用することができます。配列、レコード、線形テーブル、キュー、コレクションは全てLuaのテーブルで表現することができます。       

1. 配列

Luaでは、テーブルのインデックスに整数を使用することで配列を実装することができます。そのため、Luaにおける配列は、サイズが固定されておらず、例えば、以下のようになります。

コピーコード コードは以下の通りです。

 a = {}
 for i = 1, 1000 do
     a[i] = 0
 end
 print("The length of array 'a' is " . #a)
 -- The length of array 'a' is 1000

    Luaでは、配列の開始インデックスに任意の数値を指定できますが、原則として1がその開始インデックス値として使用されます。そして、Luaの組み込み関数や関数の多くはこの機能に依存しているので、無闇にこのルールを確保するようにしましょう。次のメソッドは、テーブル・コンストラクタを介して配列を作成し、初期化するものです。
コピーコード コードは以下の通りです。

    squares = {1, 4, 9, 16, 25}

 2. 二次元配列。

    Luaでテーブルを使って多次元配列を構成するには、2つの方法があります。1つ目は多次元配列をquot;array of arrays"で実装する方法で、1次元配列の各要素はtableオブジェクトでもあります。

コピーコード コードは以下の通りです。

mt = {}
for i = 1, N do
    mt[i] = {}
    for j = 1, M do
        mt[i][j] = i * j
    end
end

    2つ目の方法は,2次元配列のインデックスを,2次元目のステップサイズとして固定定数で展開するもので,例えば

コピーコード コードは以下の通りです。

 mt = {}
 for i = 1, N do
     for j = 1, M do
         mt[(i - 1) * M + j] = i * j
     end
 end

3.リンクされたテーブル。

テーブルは動的な存在であるため、Luaでは連鎖したテーブルを実装するのが便利です。各ノードはテーブルとして表現され、"link"はノード内の単なるフィールドで、次のような他のテーブルへの参照を含んでいます。

コピーコード コードは以下の通りです。

list = nil
for i = 1, 10 do
    list = { next = list, value = i}
end

local l = list
while l do
    print(l.value)
    l = l.next
end

 4. 待ち行列と双方向性待ち行列。

    Luaでキューを実装する簡単な方法は、テーブル・ライブラリの関数insertとremoveを使うことです。しかし、この方法では後続の要素が移動してしまうため、キューに大量のデータがある場合はお勧めできません。以下のコードは、より効率的な実装方法です、例.

コピーコード コードは以下の通りです。

List = {}

function List.new()
    return {first = 0, last = -1}
end

function List.pushFront(list, value)
    local first = list.first - 1
    list.first = first
    list[first] = value
end

function List.pushBack(list, value)
    local last = list.last + 1
    list.last = last
    list[last] = value
end

function List.popFront(list)
    local first = list.first
    if first > list.last then
        error("List is empty")
    end
    local value = list[first]
    list[first] = nil
    list.first = first + 1
    return value
end

function List.popBack(list)
    local last = list.last
    if list.first > last then
        error("List is empty")
    end
    local value = list[last]
    list[last] = nil
    list.last = last - 1
    return value
end

  5. セット・パッケージ(バッグ)。

    Luaでテーブルを使ったコレクションを実装するのは非常に簡単で、以下のコードをご覧ください。

コピーコード コードは以下の通りです。

    reserved = { ["while"] = true, ["end"] = true, ["function"] = true, }
    if not reserved["while"] then
        --do something
    end

    Luaではパッケージ(Bag)をMultiSetと考えることができますが、通常のコレクションと異なるのは、コンテナの中で同じキーを持つ要素を複数回出現させることができる点です。次のコードは、テーブル内の要素にカウンターを追加することで、このデータ構造の実装をシミュレートしています。
コピーコード コードは以下の通りです。

function insert(bag, element)
    bag[element] = (bag[element] or 0) + 1
end

function remove(bag, element)
    local count = bag[element]
    bag[element] = (count and count > 1) and count - 1 or nil
end

 6. StringBuilderです。
    Luaで複数の文字列を連結して1つの大きな文字列にしたい場合は、次のようにします。

コピーコード コードは以下の通りです。

 local buff = ""
 for line in io.lines() do
     buff = buff ... line ... "\n"
 end

 上記のコードでも問題なく動作しますが、行数が多い場合、この方法ではメモリの再割り当てやメモリ間のデータコピーが大量に発生し、結果としてパフォーマンスのオーバーヘッドが相当なものになります。実は、Javaなど多くのプログラミング言語では、文字列は不変のオブジェクトなので、この方法では、大きな文字列を複数回連結したときに、同じようにパフォーマンスの問題が発生します。この問題を解決するために、JavaではStringBuilderクラスが提供されていますが、Luaではtableのconcatメソッドを使用することで、この問題を解決できます。以下のコードを参照してください。
コピーコード コードは以下の通りです。

local t = {}
for line in io.lines() do
    t[#t + 1] = line . "\n"
end
local s = table.concat(t)

The --concat method can take two arguments, so the above approach could also be changed to
local t = {}
for line in io.lines() do
    t[#t + 1] = line
end
local s = table.concat(t,"\n")