Lua Table逆引きリファレンス:目的別コード集

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 プログラミングの一助となれば幸いです。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール