0Pricing
Lua Academy · บทเรียน

ตารางซ้อนกันและข้อมูลแบบมีโครงสร้าง

สร้างโครงสร้างซ้อนกันและเข้าถึงฟิลด์ที่อยู่ลึกลงไป

ตารางซ้อนกันและข้อมูลแบบมีโครงสร้าง เป็นบทเรียน Lua Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน 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))

เมทริกซ์แบบเบาบาง

การจัดเก็บเมทริกซ์สองมิติแบบตรงไปตรงมาจะสิ้นเปลืองหน่วยความจำเมื่ออินพุตขนาดใหญ่มีสมาชิกอยู่น้อย ให้จัดเก็บเฉพาะสมาชิกที่ไม่เป็นศูนย์ในตารางซ้อน: 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.b และ t.a มีค่าเป็น nil

ทบทวน: ตารางซ้อน

สรุป:

  • ตารางซ้อนได้โดยไม่จำกัด: t.a.b.c
  • ป้องกันการเข้าถึงข้อมูลลึก: t and t.a and t.a.b
  • ตารางเป็นชนิดข้อมูลแบบอ้างอิง — ฟังก์ชันจะแก้ไขข้อมูลโดยตรง
  • อาร์เรย์ของระเบียน: {{name=...},{name=...}}
  • เมทริกซ์แบบเบาบาง: ใช้ตารางซ้อนเพื่อประหยัดหน่วยความจำ
  • ความเท่ากันเชิงลึกต้องใช้การเปรียบเทียบแบบเรียกซ้ำ

คำถามที่พบบ่อย

บทเรียน “ตารางซ้อนกันและข้อมูลแบบมีโครงสร้าง” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “ตารางซ้อนกันและข้อมูลแบบมีโครงสร้าง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Lua Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Lua Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “ตารางซ้อนกันและข้อมูลแบบมีโครงสร้าง”

สร้างโครงสร้างซ้อนกันและเข้าถึงฟิลด์ที่อยู่ลึกลงไป คุณปฏิบัติ Lua Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Lua Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Lua Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “ตารางซ้อนกันและข้อมูลแบบมีโครงสร้าง” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Lua Academy นี้ได้ไหม

ได้ บทเรียน Lua Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ตารางในรูปแบบอาร์เรย์
  2. ตารางในรูปแบบพจนานุกรม
  3. การวนดูตารางด้วย pairs และ ipairs
  4. ตารางซ้อนกันและข้อมูลแบบมีโครงสร้าง
← กลับไปที่ Lua Academy