Lua Table逆引きリファレンス:目的別コード集
Lua における Table は、配列、連想配列、オブジェクト、データ構造など、様々な役割を果たす強力なデータ型です。その柔軟性ゆえに、特定の処理を行うための最適な Table 操作が分かりにくい場合も少なくありません。本記事では、Lua Table を活用するための逆引きリファレンスとして、目的別のコード例を豊富に紹介し、Table 操作の理解を深め、効率的なプログラミングを支援することを目的とします。
1. Table の基本操作
まずは Table の基本操作を確認しましょう。
- Table の作成:
“`lua
— 空の Table の作成
local myTable = {}
— 初期値を持つ Table の作成
local student = {
name = “太郎”,
age = 18,
grade = “3年生”
}
— 数値インデックスを持つ Table (配列) の作成
local numbers = {1, 2, 3, 4, 5}
“`
- Table へのアクセス:
“`lua
— キーを指定してアクセス
local studentName = student.name — student[“name”] と同じ
print(studentName) — 出力: 太郎
— 数値インデックスでアクセス
local firstNumber = numbers[1] — Lua の配列インデックスは 1 から始まる
print(firstNumber) — 出力: 1
— キーが存在しない場合、nil が返される
local nonexistentKey = student.address
print(nonexistentKey) — 出力: nil
“`
- Table への追加と更新:
“`lua
— 新しいキーと値を追加
student.address = “東京都”
student[“phone”] = “090-1234-5678”
— 既存のキーの値を更新
student.age = 19
— 数値インデックスで要素を追加
numbers[6] = 6
— 数値インデックスで要素を更新
numbers[3] = 10
“`
- Table からの削除:
“`lua
— キーを指定して要素を削除 (nil を代入)
student.address = nil
— 数値インデックスで要素を削除 (配列の隙間ができる)
numbers[3] = nil — {1, 2, nil, 4, 5, 6}
— table.remove() を使って配列の要素を削除 (インデックスを詰める)
table.remove(numbers, 3) — {1, 2, 4, 5, 6}
“`
- Table の長さの取得:
“`lua
— # 演算子を使って数値インデックスの Table (配列) の長さを取得
local length = #numbers
print(length) — 出力: 5
— 連想配列の長さを取得 (要素数を数える)
local count = 0
for _, _ in pairs(student) do
count = count + 1
end
print(count) — 出力: 3 (name, age, grade, phone)
“`
2. Table のイテレーション
Table の要素を効率的に処理するには、イテレーションが不可欠です。
pairs()
:
lua
-- Table のキーと値を順番に処理する
for key, value in pairs(student) do
print(key .. ": " .. value)
end
-- 出力:
-- name: 太郎
-- age: 19
-- grade: 3年生
-- phone: 090-1234-5678
pairs()
は、キーと値のペアを順番に返します。キーの順番は保証されません。連想配列のイテレーションに適しています。
ipairs()
:
lua
-- 数値インデックスの Table (配列) の要素を順番に処理する
for index, value in ipairs(numbers) do
print(index .. ": " .. value)
end
-- 出力:
-- 1: 1
-- 2: 2
-- 3: 4
-- 4: 5
-- 5: 6
ipairs()
は、数値インデックス 1 から順番に要素を返します。Table に nil の要素があると、そこでイテレーションが止まります。配列のイテレーションに適しています。
next()
:
lua
-- Table のキーと値を順番に処理する (より低レベルな関数)
local key, value = next(student, nil)
while key do
print(key .. ": " .. value)
key, value = next(student, key)
end
-- 出力 (pairs() と同じ):
-- name: 太郎
-- age: 19
-- grade: 3年生
-- phone: 090-1234-5678
next()
は、指定されたキーの次のキーと値を返します。最初のキーを取得する場合は、第2引数に nil
を渡します。pairs()
は next()
を内部で使用しています。より柔軟なイテレーションが必要な場合に便利です。
3. Table のソート
Table の要素を特定の順序で並べ替えるには、table.sort()
を使用します。
“`lua
local numbers = {5, 2, 8, 1, 9, 4}
— 昇順にソート (デフォルト)
table.sort(numbers)
— numbers: {1, 2, 4, 5, 8, 9}
— 降順にソート (比較関数を渡す)
table.sort(numbers, function(a, b)
return a > b
end)
— numbers: {9, 8, 5, 4, 2, 1}
— 複雑なオブジェクトの Table をソート (比較関数をカスタマイズ)
local students = {
{ name = “太郎”, age = 18 },
{ name = “花子”, age = 20 },
{ name = “次郎”, age = 19 }
}
— 年齢順にソート
table.sort(students, function(a, b)
return a.age < b.age
end)
for _, student in ipairs(students) do
print(student.name .. “: ” .. student.age)
end
— 出力:
— 太郎: 18
— 次郎: 19
— 花子: 20
“`
table.sort()
は、第1引数にソート対象の Table を、第2引数に比較関数を受け取ります。比較関数は、2つの要素を引数に取り、最初の要素が2番目の要素よりも小さい場合に true
を、そうでない場合に false
を返す必要があります。比較関数を省略した場合は、デフォルトの <
演算子を使用して昇順にソートされます。
4. Table のコピー
Table は参照型であるため、単純な代入ではコピーを作成できません。=
で代入すると、同じ Table を指す別の変数を作成するだけです。Table のコピーを作成するには、いくつかの方法があります。
- シャローコピー:
“`lua
— 新しい Table を作成し、元の Table のキーと値をコピーする
local originalTable = {a = 1, b = 2, c = 3}
local shallowCopy = {}
for key, value in pairs(originalTable) do
shallowCopy[key] = value
end
— shallowCopy は originalTable とは別の Table
shallowCopy.a = 10
print(originalTable.a) — 出力: 1
print(shallowCopy.a) — 出力: 10
— しかし、ネストされた Table は参照を共有する
originalTable.d = {x = 4, y = 5}
shallowCopy.d = originalTable.d
shallowCopy.d.x = 40
print(originalTable.d.x) — 出力: 40
print(shallowCopy.d.x) — 出力: 40
“`
シャローコピーは、Table の最上位のキーと値を新しい Table にコピーします。しかし、値が Table の場合は、その Table の参照をコピーします。つまり、元の Table とコピーされた Table は、ネストされた Table を共有します。
- ディープコピー (再帰的なコピー):
“`lua
— Table の要素を再帰的にコピーする関数
local function deepCopy(original)
local copy = {}
for key, value in pairs(original) do
if type(value) == “table” then
copy[key] = deepCopy(value) — 再帰的にコピー
else
copy[key] = value
end
end
return copy
end
local originalTable = {a = 1, b = 2, c = {x = 4, y = 5}}
local deepCopyTable = deepCopy(originalTable)
— deepCopyTable は originalTable とは完全に独立した Table
deepCopyTable.c.x = 40
print(originalTable.c.x) — 出力: 4
print(deepCopyTable.c.x) — 出力: 40
“`
ディープコピーは、Table のすべての要素 (ネストされた Table を含む) を再帰的にコピーします。元の Table とコピーされた Table は、完全に独立した Table になります。ただし、ディープコピーは、循環参照を持つ Table に対しては使用できません。
5. Table のフィルタリング
Table から特定の条件を満たす要素だけを抽出するには、フィルタリングを行います。
“`lua
local numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
— 偶数だけを抽出する
local evenNumbers = {}
for _, value in ipairs(numbers) do
if value % 2 == 0 then
table.insert(evenNumbers, value)
end
end
— evenNumbers: {2, 4, 6, 8, 10}
— 5より大きい数だけを抽出する
local largeNumbers = {}
for _, value in ipairs(numbers) do
if value > 5 then
table.insert(largeNumbers, value)
end
end
— largeNumbers: {6, 7, 8, 9, 10}
— Table をフィルタリングする関数
local function filterTable(table, predicate)
local result = {}
for key, value in pairs(table) do
if predicate(key, value) then
result[key] = value
end
end
return result
end
— 名前が “太郎” で始まる学生だけを抽出する
local students = {
{ name = “太郎”, age = 18 },
{ name = “花子”, age = 20 },
{ name = “太郎次郎”, age = 19 }
}
local taroStudents = filterTable(students, function(_, student)
return string.sub(student.name, 1, 1) == “太” — 名前が “太” で始まるか
end)
for _, student in pairs(taroStudents) do
print(student.name .. “: ” .. student.age)
end
— 出力:
— 1: 太郎: 18
— 3: 太郎次郎: 19
“`
フィルタリングは、Table の各要素に対して条件を評価し、条件を満たす要素だけを新しい Table に追加します。
6. Table のマッピング
Table の各要素を別の値に変換するには、マッピングを行います。
“`lua
local numbers = {1, 2, 3, 4, 5}
— 各要素を2倍にする
local doubledNumbers = {}
for _, value in ipairs(numbers) do
table.insert(doubledNumbers, value * 2)
end
— doubledNumbers: {2, 4, 6, 8, 10}
— Table をマッピングする関数
local function mapTable(table, transform)
local result = {}
for key, value in pairs(table) do
result[key] = transform(key, value)
end
return result
end
— 学生の名前だけを抽出する
local students = {
{ name = “太郎”, age = 18 },
{ name = “花子”, age = 20 },
{ name = “次郎”, age = 19 }
}
local studentNames = mapTable(students, function(_, student)
return student.name
end)
for _, name in pairs(studentNames) do
print(name)
end
— 出力:
— 1: 太郎
— 2: 花子
— 3: 次郎
“`
マッピングは、Table の各要素を変換関数に渡し、変換された値を新しい Table に追加します。
7. Table の削減 (集計)
Table の要素を単一の値に集計するには、削減 (集計) を行います。
“`lua
local numbers = {1, 2, 3, 4, 5}
— 要素の合計を計算する
local sum = 0
for _, value in ipairs(numbers) do
sum = sum + value
end
print(sum) — 出力: 15
— Table を削減する関数
local function reduceTable(table, accumulator, initialValue)
local result = initialValue
for key, value in pairs(table) do
result = accumulator(result, key, value)
end
return result
end
— 学生の平均年齢を計算する
local students = {
{ name = “太郎”, age = 18 },
{ name = “花子”, age = 20 },
{ name = “次郎”, age = 19 }
}
local totalAge = reduceTable(students, function(acc, _, student)
return acc + student.age
end, 0)
local averageAge = totalAge / #students
print(averageAge) — 出力: 19
“`
削減 (集計) は、Table の各要素と累積値を集計関数に渡し、その結果を新しい累積値として更新します。最終的な累積値が削減の結果となります。
8. Table の結合
複数の Table を結合して、1つの Table を作成するには、Table の結合を行います。
“`lua
local table1 = {a = 1, b = 2}
local table2 = {c = 3, d = 4}
— 2つの Table を結合する
local combinedTable = {}
for key, value in pairs(table1) do
combinedTable[key] = value
end
for key, value in pairs(table2) do
combinedTable[key] = value
end
— combinedTable: {a = 1, b = 2, c = 3, d = 4}
— table.insert() を使って配列を結合する
local array1 = {1, 2, 3}
local array2 = {4, 5, 6}
for _, value in ipairs(array2) do
table.insert(array1, value)
end
— array1: {1, 2, 3, 4, 5, 6}
— Table を結合する関数
local function combineTables(…)
local result = {}
for i = 1, select(“#”, …) do
local table = select(i, …)
for key, value in pairs(table) do
result[key] = value
end
end
return result
end
local combinedTable2 = combineTables(table1, table2)
— combinedTable2: {a = 1, b = 2, c = 3, d = 4}
“`
Table の結合は、複数の Table のキーと値を新しい Table にコピーします。キーが重複する場合は、後の Table の値で上書きされます。
9. その他の Table 操作
- Table の空判定:
“`lua
local myTable = {}
— Table が空かどうかを確認する
local isEmpty = next(myTable) == nil
print(isEmpty) — 出力: true
myTable.a = 1
isEmpty = next(myTable) == nil
print(isEmpty) — 出力: false
“`
next()
を使用して、Table に要素が存在するかどうかを確認できます。
- キーの存在確認:
“`lua
local student = { name = “太郎”, age = 18 }
— キーが存在するかどうかを確認する
local hasName = student.name ~= nil
local hasAddress = student.address ~= nil
print(hasName) — 出力: true
print(hasAddress) — 出力: false
“`
nil
と比較してキーの存在を確認できます。
- Table のクリア:
“`lua
local myTable = {a = 1, b = 2, c = 3}
— Table をクリアする
for key, _ in pairs(myTable) do
myTable[key] = nil
end
“`
Table のすべてのキーに nil
を代入することで、Table をクリアできます。
まとめ
本記事では、Lua Table を活用するための様々な操作について、目的別のコード例とともに解説しました。Table の基本的な操作から、イテレーション、ソート、コピー、フィルタリング、マッピング、削減、結合など、高度な操作までを網羅的にカバーしました。これらの知識を習得することで、Lua プログラミングにおける Table の利用効率が向上し、より複雑なデータ構造やアルゴリズムを実装できるようになるでしょう。ぜひ、本記事を参考に、Lua Table を自在に操り、創造的なプログラミングを楽しんでください。
補足:table.move
(Lua 5.3 以降)
Lua 5.3 から table.move
が導入されました。これは配列の一部を別の場所に効率的にコピーするために設計された関数です。
lua
local a = {1, 2, 3, 4, 5}
table.move(a, 1, 3, 4) -- a[4], a[5], a[6] に a[1], a[2], a[3] をコピー
-- a は {1, 2, 3, 1, 2, 3} になる
table.move(a, f, e, t)
はテーブル a
のインデックス f
から e
までの要素をインデックス t
から始める場所にコピーします。この関数は、コピー元の範囲とコピー先の範囲が重なっている場合でも正しく動作します。大規模な配列操作において、table.move
は効率的な選択肢となります。
この逆引きリファレンスが、あなたの Lua プログラミングの一助となれば幸いです。