Lua Academy · レッスン

ネストしたテーブルと構造化データ

入れ子構造を作成し、深い階層のフィールドにアクセスします。

レッスン 4/412 ステップ

「ネストしたテーブルと構造化データ」はCoddyKit上の無料Lua Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLua Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Lua Academyコースには全4レッスンが含まれています。

ネストしたテーブルの基礎

テーブルは値として別のテーブルを含むことができ、任意に深い構造を作れます。ドットやブラケットを連結してネストしたフィールドにアクセスします。途中のテーブルがないとエラーになるため、深いフィールドにアクセスする前に、親テーブルが存在することを必ず確認してください。

local company = {
  name = "CoddyKit",
  address = {
    city = "Istanbul",
    country = "Turkey",
    zip = "34000"
  },
  employees = 25
}

print(company.name)            -- CoddyKit
print(company.address.city)    -- Istanbul
print(company["address"]["zip"]) -- 34000

安全な深いアクセス

nil値のフィールドにアクセスすると、"attempt to index a nil value"でクラッシュします。andの短絡評価を使って、t and t.a and t.a.bのように防止できます。コードベースによっては、キーの連鎖を安全にたどるget(t, ...)ヘルパーを定義しています。

local function get(t, ...)
  local cur = t
  for _, key in ipairs({...}) do
    if type(cur) ~= "table" then return nil end
    cur = cur[key]
  end
  return cur
end

local data = {user = {profile = {age = 30}}}
print(get(data, "user", "profile", "age"))    -- 30
print(get(data, "user", "missing", "field"))  -- nil

レコードの配列

よくあるパターンは、テーブル(レコード)の配列です。各要素は名前付きフィールドを持つテーブルです。ipairsで反復し、名前でフィールドにアクセスします。これは、オブジェクトの配列や構造体のリストに相当するLuaのデータ構造です。

local users = {
  {id=1, name="Alice", score=95},
  {id=2, name="Bob",   score=87},
  {id=3, name="Carol", score=91},
}

for _, user in ipairs(users) do
  print(user.id, user.name, user.score)
end

ネストしたテーブルの動的な構築

必要に応じて内部テーブルを作成し、ネストした構造を段階的に構築します。内部テーブルに追加する前に、必ずテーブルを初期化してください。よくある間違いは、先に内部テーブルを作成せず、nilをインデックスしようとすることです。

local tree = {}
tree.root = {value = 10}
tree.root.left = {value = 5}
tree.root.right = {value = 15}
tree.root.left.left = {value = 2}

print(tree.root.value)            -- 10
print(tree.root.left.value)       -- 5
print(tree.root.left.left.value)  -- 2

JSON風の設定としてのテーブル

Luaのテーブルは、JSONやYAMLと同様に、設定ファイルによく使われます。ファイルはテーブルを返し、アプリケーションはdofile()またはrequire()で読み込みます。ネストしたテーブルで、設定の階層を表現します。

-- config.lua (returned table)
local config = {
  server = {
    host = "0.0.0.0",
    port = 8080,
    ssl  = false,
  },
  db = {
    host = "localhost",
    name = "appdb",
    pool_size = 10,
  },
  logging = { level = "info", file = "/var/log/app.log" }
}

print(config.server.port)      -- 8080
print(config.db.pool_size)    -- 10

隣接リストとしてのグラフ

グラフはテーブルのテーブルとして表現できます。各キーがノードで、その値が隣接ノードのリストです。この隣接リスト表現は、疎グラフでメモリ効率がよく、Luaで扱いやすい方法です。

local graph = {
  A = {"B", "C"},
  B = {"A", "D"},
  C = {"A", "D"},
  D = {"B", "C"},
}

-- BFS from A
local visited = {A=true}
local queue = {"A"}
while #queue > 0 do
  local node = table.remove(queue, 1)
  io.write(node .. " ")
  for _, neighbor in ipairs(graph[node]) do
    if not visited[neighbor] then
      visited[neighbor] = true
      queue[#queue+1] = neighbor
    end
  end
end
print()  -- A B C D

ネストしたフィールドの変更

親テーブルにアクセスしてキーに値を代入すると、ネストしたフィールドを変更できます。テーブルは参照渡しされるため、テーブルを受け取った関数はその内容を直接変更でき、呼び出し元からも変更が確認できます。

local player = {name="Hero", stats={hp=100, mp=50, atk=20}}

local function takeDamage(p, dmg)
  p.stats.hp = math.max(0, p.stats.hp - dmg)
end

takeDamage(player, 35)
print(player.stats.hp)   -- 65

player.stats.atk = player.stats.atk + 5
print(player.stats.atk)  -- 25

ネストしたテーブルのシリアライズ

ネストしたテーブルを文字列に変換すると、デバッグやログ出力に役立ちます。単純な再帰的シリアライザーで任意の深さに対応できますが、循環(循環参照)は処理できません。

local function serialize(val, indent)
  indent = indent or 0
  local pad = string.rep("  ", indent)
  if type(val) ~= "table" then
    return tostring(val)
  end
  local parts = {"{"}
  for k, v in pairs(val) do
    parts[#parts+1] = pad.."  "..tostring(k).."="..serialize(v,indent+1)
  end
  parts[#parts+1] = pad.."}"
  return table.concat(parts, "\n")
end
local data = {x=1, nested={y=2, z=3}}
print(serialize(data))

疎行列

2次元行列をそのまま保存すると、大規模で疎な入力ではメモリを無駄に消費します。ネストしたテーブルにゼロ以外のエントリだけを保存し、matrix[row][col] = valueのように表現します。ほとんどの値がゼロの場合、大規模な行列を効率よく表現できます。

local function newMatrix()
  return setmetatable({}, {__index=function(t,k)
    local row = {}
    rawset(t, k, row)
    return row
  end})
end

local m = newMatrix()
m[1][1] = 5
m[3][7] = 12
m[100][200] = 99

print(m[1][1])    -- 5
print(m[3][7])    -- 12
print(m[2][5])    -- nil (sparse: no value)

深い等価性のチェック

テーブルは値ではなく、==で参照によって比較されます。ネストしたテーブルを構造的に比較するには、各キーと値を比較し、ネストしたテーブルに対して再帰する等価性関数を作成します。

local function deepEqual(a, b)
  if type(a) ~= type(b) then return false end
  if type(a) ~= "table" then return a == b end
  for k, v in pairs(a) do
    if not deepEqual(v, b[k]) then return false end
  end
  for k in pairs(b) do
    if a[k] == nil then return false end
  end
  return true
end
print(deepEqual({1,{2,3}},{1,{2,3}}))  -- true
print(deepEqual({1,{2,3}},{1,{2,4}}))  -- false

クイックチェック

t.aがnilのときにt.a.bへアクセスすると、何が起こりますか?

復習:ネストしたテーブル

まとめ:

  • テーブルは任意の深さにネストできます:t.a.b.c
  • 深いアクセスを防御します:t and t.a and t.a.b
  • テーブルは参照型です。関数は内容を直接変更します
  • レコードの配列:{{name=...},{name=...}}
  • 疎行列:メモリ効率のためにネストしたテーブルを使います
  • 深い等価性には再帰的な比較が必要です
無料で開始

AI チューターと学ぶ Lua — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
40
レッスン
159

よくある質問

「ネストしたテーブルと構造化データ」レッスンは無料ですか?

はい。「ネストしたテーブルと構造化データ」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Lua Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Lua Academyコースには全4レッスンが含まれています。

「ネストしたテーブルと構造化データ」で何を学びますか?

入れ子構造を作成し、深い階層のフィールドにアクセスします。 ブラウザで直接実行するハンズオンコードでLua Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Lua Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのLua Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「ネストしたテーブルと構造化データ」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このLua Academyレッスンでコードを書いて実行できますか?

はい。すべてのLua Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 配列としてのテーブル
  2. 辞書としてのテーブル
  3. pairsとipairsによるテーブルの反復処理
  4. ネストしたテーブルと構造化データ
← Lua Academyに戻る