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