こんにちは、ロブスタのハルです!
前回の講座ではテーブルに対して使えるメソッドや機能の紹介をしました。
今回はループ処理とテーブルを組み合わせた場合の機能について解説します。
前回の講座を見ていない方はこちらからご覧ください。
反復処理①(配列モード)
テーブルのように複数の値を持っているオブジェクトからその中身の要素を取り出すという動作を繰り返し行うには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の場合を考えます。
インデックスi | itemCount + 1 – i |
1 | 5+1-1=5 |
2 | 5+1-2=4 |
3 | 5+1-3=3 |
4 | 5+1-4=2 |
5 | 5+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文を使うことで手軽にテーブルに変更を加えることができるようになりましたね。
あるテーブルの要素全部に同じ処理をしたいとか、テーブルからある条件の要素だけを取り出してきたいという場合には今回の記事を思い出してもらえればと思います。
次回は多次元テーブルとネストについて解説しようと思います。
コメント