วิธีที่มีประสิทธิภาพที่สุดในการตรวจสอบว่าตาราง Lua ว่างเปล่า (ไม่มีรายการ) หรือไม่?


120

วิธีใดที่มีประสิทธิภาพที่สุดในการพิจารณาว่าตารางว่างเปล่า (นั่นคือปัจจุบันไม่มีทั้งค่าสไตล์อาร์เรย์หรือค่าสไตล์คำสั่ง)

ขณะนี้ฉันใช้next():

if not next(myTable) then
    -- Table is empty
end

มีวิธีที่มีประสิทธิภาพมากกว่านี้หรือไม่?

หมายเหตุ: ตัว#ดำเนินการไม่เพียงพอที่นี่เนื่องจากมันทำงานเฉพาะกับค่าสไตล์อาร์เรย์ในตารางดังนั้นจึง#{test=2}แยกไม่ออก#{}เนื่องจากทั้งสองส่งคืน 0 โปรดทราบว่าการตรวจสอบว่าตัวแปรตารางnilไม่เพียงพอหรือไม่เนื่องจากฉันไม่ได้มองหา ค่าศูนย์ แต่เป็นตารางที่มี 0 รายการ (เช่น{})

คำตอบ:


151

รหัสของคุณมีประสิทธิภาพ แต่ผิดพลาด (พิจารณา{[false]=0}) รหัสที่ถูกต้องคือ

if next(myTable) == nil then
   -- myTable is empty
end

เพื่อประสิทธิภาพสูงสุดคุณจะต้องผูกnextกับตัวแปรท้องถิ่นเช่น

...
local next = next 
...
... if next(...) ...

1
จุดที่ดีเกี่ยวกับความถูกต้องทางเทคนิค ในกรณีเฉพาะที่ฉันใช้รหัสเดิมfalseจะไม่ใช่คีย์ที่คาดหวังดังนั้นการใช้if notงานได้ดี แต่ฉันอาจจะสร้างนิสัยในการเปรียบเทียบnilแทนในอนาคตเช่นเดียวกับนิสัยที่ดี และใช่ฉันได้ผูกฟังก์ชันยูทิลิตี้ทั่วไปเข้ากับตัวแปรท้องถิ่นเพื่อความเร็ว ขอบคุณสำหรับข้อมูล
อำพัน

1
ฉันพบว่ายากที่จะเห็นด้วยกับความผิดเมื่อรหัสทำงานได้ตามที่ตั้งใจ
RD Alkire

4
ทำไมเราถึงได้รับความเร็วจากการทำlocal next?
Moberg

2
@Moberg นี่คือสาเหตุที่ LUA จัดการกับเนมสเปซ รุ่นที่โง่ลงมากมันจะปีนขึ้นไปบนตารางท้องถิ่นก่อนหรือไม่ดังนั้นหากมีlocal nextบล็อกปัจจุบันก็จะใช้สิ่งนั้นจากนั้นปีนขึ้นไปยังบล็อกถัดไปและทำซ้ำ เมื่อไม่อยู่ในพื้นที่ก็จะใช้ Global Namespace เท่านั้น นี่เป็นเวอร์ชันที่ถูกลดทอนลง แต่ในท้ายที่สุดก็หมายถึงความแตกต่างในเรื่องความเร็วของโปรแกรม
ATaco

@ Moberg เวอร์ชันที่ลดลงน้อยลงในบริบทของ lua 5.2 & 5.3 คือคนที่ไม่ใช่คนในพื้นที่จะเป็น upvals หรือ _ENV lookups การอัพค่าต้องผ่านเลเยอร์พิเศษของอินดิเคเตอร์ในขณะที่การค้นหา _ENV เป็นการค้นหาตาราง ในขณะที่ท้องถิ่นจะลงทะเบียนใน VM
Demur Rumed

1

ความเป็นไปได้อย่างหนึ่งคือการนับจำนวนองค์ประกอบโดยใช้คีย์ "newindex" ที่สามารถตรวจจับได้ เมื่อกำหนดสิ่งที่ไม่ได้nilให้เพิ่มตัวนับ (ตัวนับสามารถอยู่ใน metatable เช่นกัน) และเมื่อกำหนดให้nilลดตัวนับ

การทดสอบตารางว่างจะเป็นการทดสอบตัวนับด้วย 0

นี่คือตัวชี้ไปยังเอกสารที่ตรวจพบได้

ฉันชอบวิธีแก้ปัญหาของคุณและฉันไม่สามารถสรุปได้ว่าโซลูชันของฉันโดยรวมเร็วขึ้น


5
คำถามเดิมไม่ได้เกี่ยวกับการนับเฉพาะรายการ "อาร์เรย์"
lhf

3
ข้อเสนอแนะของ 0x6 ไม่เฉพาะเจาะจงกับรายการสไตล์อาร์เรย์ (ดัชนีใหม่ใช้ได้กับทั้งดัชนีที่เป็นตัวเลขและไม่ใช่ตัวเลข) อย่างไรก็ตามปัญหาหลักจะตรวจพบเมื่อnilได้รับมอบหมายเนื่องจาก __newindex จะไม่ทริกเกอร์หากมีคีย์อยู่แล้วในตาราง
แอมเบอร์

3
เพื่อให้เคล็ดลับนี้ใช้งานได้ metatable จะต้องใช้ทั้งสองอย่าง__indexและ__newindexจัดเก็บข้อมูลจริงในตารางเงาและทำให้ตารางจริงว่างเปล่าจึง__indexจะถูกเรียกใช้เลย เมื่อคิดออกมาดัง ๆ ฉันสงสัยว่าค่าใช้จ่ายที่เพิ่มขึ้นของการค้นหาทุกครั้งจะไม่คุ้มค่า
RBerteig

0

นี่อาจเป็นสิ่งที่คุณต้องการ:

function table.empty (self)
    for _, _ in pairs(self) do
        return false
    end
    return true
end

a = { }
print(table.empty(a))
a["hi"] = 2
print(table.empty(a))
a["hi"] = nil
print(table.empty(a))

เอาท์พุท:

true
false
true

11
next()มีประสิทธิภาพมากขึ้น (และรัดกุมมากขึ้นกว่า) pairs()วนลูป
อำพัน

8
ในความเป็นจริงการวนซ้ำpairs() เป็นหลักเพียงแค่ใช้next()เทคนิค แต่มีค่าใช้จ่ายมากกว่า
พิรุธ

7
นอกจากนี้tableไม่แนะนำให้เขียนลงในไลบรารีมาตรฐาน
Ti Strga

-1

ดีกว่าที่จะหลีกเลี่ยงการประเมิน __eq ถ้ามากเกินไป

if rawequal(next(myTable), nil) then
   -- myTable is empty
end

หรือ

if type(next(myTable)) == "nil" then
   -- myTable is empty
end

1
ฉันเป็น Lua noob ที่พยายามเข้าใจว่าทำไมคำตอบนี้จึงถูกโหวตให้ไม่ลง ฉันเดาว่าเป็นเพราะใน Lua "ถ้าวัตถุสองชิ้นมีวิธีการเปลี่ยนแปลงที่แตกต่างกันการดำเนินการความเท่าเทียมกันจะส่งผลให้เป็นเท็จโดยไม่ต้องเรียก metamethod ใด ๆ " (คำพูดอยู่ด้านล่างสุดของหน้านี้จาก Programming in Lua บน lua.org ) นั่นทำให้ความจำเป็นในการหลีกเลี่ยง __eq เกินพิกัดสำหรับศูนย์หรือไม่?
SansWit

-1

ลองงูทำงานให้ฉัน

serpent = require 'serpent'

function vtext(value)
  return serpent.block(value, {comment=false})
end

myTable = {}

if type(myTable) == 'table' and vtext(myTable) == '{}' then
   -- myTable is empty
end

-2

แล้วเรื่องนี้ล่ะ?

if endmyTable[1] == nil then
  -- myTable is empty
end

1
สิ่งนี้จะไม่ทำงานบนตารางที่เป็นสตริงเช่นเดียวกับดัชนี
SamHoque

-3

ฉันรู้ว่ามันเก่าแล้วและฉันอาจจะเข้าใจผิดคุณ แต่คุณแค่ต้องการให้โต๊ะว่างนั่นคือเว้นแต่คุณจะตรวจสอบว่ามันเป็นและคุณไม่ต้องการหรือต้องการให้มันว่างเปล่าจริงๆ คุณสามารถล้างได้โดยการสร้างขึ้นใหม่เว้นแต่ฉันจะเข้าใจผิด ซึ่งสามารถทำได้ด้วยไวยากรณ์ด้านล่าง

yourtablename = {} -- this seems to work for me when I need to clear a table.

4
นั่นไม่ใช่คำถาม
Yu Hao

-6

ลองใช้#. ส่งคืนอินสแตนซ์ทั้งหมดที่อยู่ในตาราง หากไม่มีอินสแตนซ์ในตารางก็จะส่งคืน0

if #myTable==0 then
print('There is no instance in this table')
end

1
ผู้ถามบอกว่า#จะไม่พอเพียงที่นี่และให้เหตุผลว่าทำไม คุณช่วยอธิบายได้ไหมว่าทำไมสิ่งนี้ถึงได้รับเหตุผลเหล่านั้น
ameed

ฉันไม่รู้ฉันยังใหม่ในเรื่องนี้ดังนั้นวิธีเดียวที่ฉันรู้คือใช้ #
arthurgps2
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.