Cách hiệu quả nhất để xác định xem một bảng Lua có trống (không chứa mục nhập) hay không?


120

Cách hiệu quả nhất để xác định xem một bảng có trống không (nghĩa là hiện tại không chứa giá trị kiểu mảng hay giá trị kiểu dict)?

Hiện tại, tôi đang sử dụng next():

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

Có cách nào hiệu quả hơn không?

Lưu ý: #Toán tử này không đủ ở đây, vì nó chỉ hoạt động trên các giá trị kiểu mảng trong bảng - do đó #{test=2}không thể phân biệt được #{}vì cả hai đều trả về 0. Cũng lưu ý rằng kiểm tra xem biến bảng nilcó đủ không vì tôi không tìm kiếm giá trị nil, mà là các bảng có 0 mục nhập (tức là {}).

Câu trả lời:


151

Mã của bạn hiệu quả nhưng sai. (Hãy xem xét {[false]=0}.) Mã đúng là

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

Để đạt hiệu quả tối đa, bạn sẽ muốn liên kết nextvới một biến cục bộ, ví dụ:

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

1
Điểm tốt về tính đúng kỹ thuật; trong những trường hợp cụ thể mà tôi đang sử dụng mã gốc, falsesẽ không phải là một khóa mong đợi để nó if nothoạt động tốt, nhưng có lẽ tôi sẽ tạo thói quen so sánh với nilthay thế trong tương lai, như một thói quen tốt. Và vâng, tôi đã ràng buộc các chức năng tiện ích phổ biến với các vars cục bộ để tăng tốc độ. Cảm ơn vì đầu vào mặc dù.
Amber

1
Tôi thấy khó đồng ý với sai quấy khi mã hoạt động như dự kiến
RD Alkire

4
Tại sao chúng ta đạt được tốc độ bằng cách làm gì local next?
Moberg

2
@Moberg Điều này là do cách LUA xử lý không gian tên của nó. Phiên bản rất ngu ngốc, trước tiên nó sẽ leo lên các bảng cục bộ, vì vậy nếu có một local nexttrong khối hiện tại, nó sẽ sử dụng nó, sau đó leo lên khối tiếp theo và lặp lại. Sau khi ra khỏi người dân địa phương, nó sẽ chỉ sử dụng Không gian tên toàn cầu. Đây là một phiên bản ngu ngốc của nó, nhưng cuối cùng, nó chắc chắn có nghĩa là sự khác biệt về tốc độ chương trình.
ATaco

@Moberg phiên bản ít bị lãng quên hơn, trong ngữ cảnh lua 5.2 & 5.3, là những người không phải là người dân địa phương là các bản nâng cấp hoặc tra cứu _ENV. Việc nâng cấp phải trải qua một lớp bổ sung của hướng dẫn, trong khi tra cứu _ENV là tra cứu bảng. Trong khi địa phương là một sổ đăng ký trong VM
Demur Rumed vào

1

Một khả năng là đếm số phần tử, bằng cách sử dụng khóa "newindex" có thể đo được. Khi không chỉ định thứ gì đó nil, hãy tăng bộ đếm (bộ đếm cũng có thể nằm trong bộ đếm được) và khi chỉ định nil, giảm bộ đếm.

Kiểm tra bảng trống sẽ là kiểm tra bộ đếm bằng 0.

Đây là một con trỏ đến tài liệu có thể đo được

Mặc dù vậy, tôi thích giải pháp của bạn và thành thật mà nói, tôi không thể cho rằng giải pháp của tôi nói chung là nhanh hơn.


5
Câu hỏi ban đầu không phải là chỉ đếm các mục nhập "mảng".
lhf

3
Đề xuất của 0x6 không dành riêng cho các mục nhập kiểu mảng (newindex hoạt động cho cả chỉ số số và không phải số). Tuy nhiên, vấn đề chính là phát hiện khi nào nilđược gán, vì __newindex không kích hoạt nếu khóa đã tồn tại trong bảng.
Amber

3
Để thủ thuật này hoạt động, có thể gặp phải thực hiện cả hai __index__newindex, lưu trữ dữ liệu thực tế trong một bảng bóng và giữ cho bảng thực trống để nó __indexsẽ được gọi ra. Suy nghĩ lung tung, tôi nghi ngờ rằng chi phí tăng lên của mỗi lần tra cứu không thể xứng đáng.
RBerteig

0

Đây có thể là những gì bạn muốn:

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))

Đầu ra:

true
false
true

11
next()hiệu quả hơn (và ngắn gọn hơn) so với lặp lại pairs().
Amber

8
Trong thực tế, Looping trên pairs() chủ yếu chỉ sử dụng các next()kỹ thuật, nhưng với chi phí hơn.
dubiousjim

7
Ngoài ra, việc ghi vào tablethư viện tiêu chuẩn không được khuyến khích.
Ti Strga

-1

tốt hơn để tránh đánh giá __eq nếu quá tải.

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

hoặc là

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

1
Tôi là một Lua noob đang cố gắng hiểu tại sao câu trả lời này lại bị bỏ phiếu. Tôi đoán đó là vì trong Lua, "nếu hai đối tượng có metamethod khác nhau, thì phép toán bình đẳng dẫn đến false, thậm chí không cần gọi bất kỳ metamethod nào". (Trích dẫn ở cuối trang này từ Lập trình trong Lua trên lua.org ). Điều đó có loại bỏ sự cần thiết phải tránh quá tải __eq cho nil không?
SansWit

-1

thử con rắn, làm việc cho tôi

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

Còn cái này thì sao ?

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

1
Điều này sẽ không hoạt động trên một bảng có chuỗi như chỉ mục
SamHoque

-3

Tôi biết điều này là cũ và tôi có thể hiểu nhầm bạn bằng cách nào đó, nhưng bạn chỉ muốn cái bàn trống, nghĩa là, trừ khi bạn chỉ kiểm tra xem nó có đúng không và bạn không thực sự muốn hoặc không cần nó để trống, bạn có thể xóa nó bằng cách đơn giản tạo lại nó, trừ khi tôi nhầm. điều này có thể được thực hiện với cú pháp dưới đây.

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

4
Đó không phải là câu hỏi.
Yu Hao

-6

Hãy thử sử dụng #. Nó trả về tất cả các trường hợp trong một bảng. Nếu không có trường hợp nào trong bảng, thì nó sẽ trả về0

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

1
Người hỏi nói rằng điều đó #sẽ không đủ ở đây, và đưa ra lý do tại sao; bạn có thể giải thích tại sao điều này xoay quanh những lý do?
ameed

cũng ... tôi không know.I mới trong này vì vậy cách duy nhất tôi biết là sử dụng #
arthurgps2
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.