【Lua言語講座】21.ループとテーブルの組み合わせ

Lua言語講座

こんにちは、ロブスタのハルです!
前回の講座ではテーブルに対して使えるメソッドや機能の紹介をしました。
今回はループ処理とテーブルを組み合わせた場合の機能について解説します。
前回の講座を見ていない方はこちらからご覧ください。

反復処理①(配列モード)

テーブルのように複数ふくすうの値を持っているオブジェクトからその中身の要素ようそを取り出すという動作をり返し行うにはforフォーinイン文を使います。

今までのfor文とは若干じゃっかん形がちがいます。

for インデックス(キー), 値 in テーブル do
    処理
end

例えば、テーブルの中のインデックスと値を表示したい場合には次のようになります。

local array = {"a", "b", "c", "d", "e"}

-- indexとvalueはiとvのように省略して書く人も多い
for index, value in array do
    print(index, value)
end

配列モードのテーブルのインデックスと値をそれぞれ変数indexインデックス, 変数valueバリューに代入してfor文内の処理を行うという動作をarrayアレイの要素数だけ繰り返します。

また、これまでのfor文を使いたい場合には#演算子を組み合わせます。

local array = {"a", "b", "c", "d", "e"}

for index = 1, #array do
    print(index, array[index])
end

#arrayでarrayの要素数を取ってこれるので、indexが1からarrayの要素数(今回は5)回繰り返されることになります。

反復処理①(連想配列モード)

連想配列れんそうはいれつモードで同じようなことをやりたい場合はpairsペアーズ関数を使います。

local dict = {
    apple = 100,
    banana = 120,
    orange = 80
}

for key, value in pairs(dict) do
    print(key, value)
end

pairs関数は連想配列モードのテーブルにしか使えません
配列モードのテーブルに対して使うとエラーの原因になるので間違わないようにしましょう。

反復処理②(ipairs)

配列モードの反復処理はipairsアイペアーズ関数を使うこともできます。

local array = {"a", "b", "c", "d", "e"}

for i, v in ipairs(array) do
    print(i, v)
end

ipairs関数は配列モードのテーブルにしか使えません
連想配列モードのテーブルに対して使うとエラーの原因になるので間違わないようにしましょう。

ipairsのiはインデックスのiと覚えておくと間違えにくいと思います。

テーブルの結合

2つのテーブルを合体させて1つのテーブルにするにはfor-in文とinsertインサートメソッドを使います。

-- t1にt2を追加する
local t1 = {1, 2}
local t2 = {3, 4}

for _, v in ipairs(t2) do
    table.insert(t1, v)
end

それぞれの動作を理解していればおそらくこのコードも理解できるはずです。

for-in文のインデックスが”_”となっていますが、これはインデックスを使わない場合によく書く方法です。

第3回で変数名として_も使えると紹介しました。なので実際は_も変数とみなされて中に数値が入っています。

つまり、私たち人間がコードを理解しやすいようにするためにあえて_と書いているのです。

同じようにvalueを使わない場合はfor i, _ in ~のように書くことができます。

テーブルを逆順にする

テーブルの要素を逆順にするにはfor-in文を使って次のように書きます。

今回はより汎用性はんようせいが高くなるように関数化しています。

local function reverseTable(t)
    local reversed = {}
    local itemCount = #t
    for i, v in ipairs(t) do
        reversed[itemCount + 1 - i] = v
    end
    return reversed
end

local myTable = {1, 2, 3, 4, 5}
local reversedTable = reverseTable(myTable)

まず、1~8行目ではreverseTableリバーステーブル関数を定義ていぎしています。

その中身は逆順ぎゃくじゅんになったテーブルを保管ほかんしておくために変数reversedリバースドと、引数としてわたされたテーブルの要素を保管しておくための変数itemCountアイテムカウントを定義しています。その後for-in文とipairs関数を使って、変数reversedの一番後ろから逆順に要素vを代入しています。

例として10行目でmyTableマイテーブルを定義し、それを11行目でreverseTable関数に渡しています。

5行目のreversed[itemCount + 1 – i]について詳しく説明します。例としてitemCountが5の場合を考えます。

インデックスiitemCount + 1 – i
15+1-1=5
25+1-2=4
35+1-3=3
45+1-4=2
55+1-5=1

上の表のようにインデックスiが1増えるごとにitemCount + 1 – iが5, 4, 3, 2, 1とカウントダウンされていることがわかりますね。つまり、reversedの一番後ろから順番にvが入っていくことになります。

テーブルのフィルタリング

特定とくてい条件じょうけんに合ったテーブルの要素を取り出すにはfor-in文とpairs関数、そしてinsert文を使って次のようにします。こちらも関数化しています。

今回は例として偶数ぐうすうのみを取り出すようにしたいと思います。

local function filterTable(t, condition)
    local filtered = {}
    for k, v in pairs(t) do
        if condition(V) then
            table.insert(filtered, v)
        end
    end
    return filtered
end

local myTable = {1, 2, 3, 4, 5}
local even = filterTable(myTable, function (v) return v % 2 == 0 end)

1~9行目ではfilterTableフィルターテーブル関数を定義しています。
引数にはテーブルtと条件用の関数conditionコンディションを設定しています。

関数の中身では結果を格納かくのうするためのテーブルをfilteredフィルタードとして宣言しておき、テーブルの中身の要素を条件用の関数conditionに渡しています。もし、conditionの戻り値がtrueトゥルーならfilteredに追加しています。

11行目ではテスト用に1~5までの自然数をmyTableに格納しています。

12行目ではfilterTable関数の戻り値をevenイーブンとして受け取る処理を書いています。
ここでは、filterTable関数の引数にmyTableと偶数かどうかを判別するための無名関数むめいかんすうを渡しています。

テーブルの各要素に関数を使う

先程のフィルタリングと同じですが、for-in文の中身の処理とフィルタリング関数に渡す関数の戻り値を変えることで好きな条件を設定できます。

例えば、以下はテーブル全体を2乗するフィルタリング関数です。

local function mapTable(t, func)
    local mapped = {}
    for k, v in pairs(t) do
        mapped[k] = func(v)
    end
    return mapped
end

local myTable = {1, 2, 3, 4, 5}
local squaredNumbers = mapTable(myTable, function(v) return v * v end)

これは基本の型として覚えておくと便利かと思います。

テーブルのキーとバリューの入れ替え

テーブルはキーとバリューのセットですが、それを入れ替えることもできます。

local function invertTable(t)
    local inverted = {}
    for k, v in pairs(t) do
        inverted[v] = k
    end
    return inverted
end

local myTable = {a = 1, b = 2, c = 3}
local invertedTable = invertTable(myTable)

4行目でキーkとバリューvを入れ替えています。

まとめ

  • 配列モードの反復処理にはpairs関数を使う
  • 連想配列モードの反復処理にはipairs関数を使う
  • テーブルの結合にはfor-in文とinsertメソッドを使う
  • テーブルを逆順にするにはfor-in文を使う
  • for-in文とpairs関数を使うことで特定の条件に合うテーブルの要素を取り出せる
  • キーとバリューを入れ替えることもできる

お疲れ様でした。今回は長くなってしまいましたがpairs関数/ipairs関数とfor-in文を使うことで手軽にテーブルに変更を加えることができるようになりましたね。

あるテーブルの要素全部に同じ処理をしたいとか、テーブルからある条件の要素だけを取り出してきたいという場合には今回の記事を思い出してもらえればと思います。

次回は多次元テーブルとネストについて解説しようと思います。

コメント

タイトルとURLをコピーしました