Найефективніший спосіб визначити, чи таблиця Lua порожня (не містить записів)?


120

Який найефективніший спосіб визначити, чи таблиця порожня (тобто наразі не містить ні значень у стилі масиву, ні значень стилю dict)?

На даний момент я використовую 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в поточному блоці є a , він використає це, потім підніметься до наступного блоку та повторіть. Після виходу з місцевих жителів лише тоді він використовуватиме глобальний простір імен. Це демпінгова версія його, але врешті-решт це, безумовно, означає різницю щодо швидкості програми.
Атако

@Moberg, менш сприятливою версією, в контексті lua 5.2 та 5.3, є те, що не місцеві жителі є або підйомами, або переглядом _ENV. Оновлення повинно пройти через додатковий шар непрямості, тоді як пошук _ENV - це пошук таблиці. Тоді як місцевий є реєстром у ВМ
Демур Румує

1

Однією з можливостей було б підрахувати кількість елементів, використовуючи метабельний ключ "newindex". Якщо щось не призначається nil, збільшуйте лічильник (лічильник може жити і в метатабелі), а при призначенні nilлічильник лічильник.

Тестування порожньої таблиці буде тестувати лічильник на 0.

Ось вказівник на документацію, що метаболізується

Мені подобається ваше рішення, і я, чесно кажучи, не можу припустити, що рішення в цілому швидше.


5
Оригінальне запитання не стосується підрахунку лише записів "масиву".
lhf

3
Пропозиція 0x6 не характерна для записів у стилі масиву (newindex працює як для числових, так і для нечислових показників). Однак головною проблемою буде виявлення, коли nilпризначено, оскільки __newindex не запускається, якщо ключ вже існує в таблиці.
Бурштин

3
Щоб цей трюк працював, метатабел повинен був би реалізувати і те, __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()техніки, але з більшою накладною витратою.
sumiousjim

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.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
Це не питання.
Ю Хао

-6

Спробуйте використовувати #. Він повертає всі екземпляри, які знаходяться в таблиці. Якщо в таблиці немає примірників, вона повертається0

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

1
Запитуючий заявляє, що #цього не вистачить, і наводить причини; Ви могли б пояснити, чому це обходить ці причини?
амедований

ну ... я не знаю. Я новачок у цьому, тому єдиним способом, який я знаю, є використання #
arthurgps2
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.