Як перевірити, чи містить таблиця елемент у Lua?


97

Чи існує метод перевірки, чи містить таблиця значення? У мене є своя (наївна) функція, але мені було цікаво, чи існує для цього щось "офіційне"? Або щось більш ефективне ...

function table.contains(table, element)
  for _, value in pairs(table) do
    if value == element then
      return true
    end
  end
  return false
end

До речі, основною причиною того, що я використовую ці функції, є використання таблиць як наборів, тобто без повторюваних елементів. Чи є ще щось, що я міг би використати?


3
що означає позначення _,?
Мартін

24
Це просто змінна "сміття" з іменем _. pairs()повертає key, value, але в цьому прикладі мені потрібно лише значення. Це свого роду домовленість (прийнята в книзі "Програмування в Lua" lua.org/pil/index.html ) використовувати цю _змінну для зберігання непотрібних вам речей.
Вукай

Я також бачив узгодження іменування змінних "сміття", що _використовуються в Python та JavaScript.
іоносферні

Відповіді:


115

Ви можете поставити значення як ключі таблиці. Наприклад:

function addToSet(set, key)
    set[key] = true
end

function removeFromSet(set, key)
    set[key] = nil
end

function setContains(set, key)
    return set[key] ~= nil
end

Там є більш повнофункціональний приклад тут .


13
Анонімний користувач запропонував таке виправлення для вашого коду: Якщо значенням у наборі із зазначеним ключем є FALSE, тоді функція setContains () повертає false, хоча в таблиці є елемент із зазначеним ключем. рядок "return set [key] ~ = nil" виправляє цю помилку.
oers

Можливо такожfunction keysOfSet(set) local ret={} for k,_ in pairs(set) do ret[#ret+1]=k end return ret end
Джессі Чисхолм

24

Враховуючи ваше уявлення, ваша функція є настільки ефективною, наскільки це можливо зробити. Звичайно, як зазначають інші (і як це практикується на мовах, старших за Lua), вирішенням вашої справжньої проблеми є зміна представництва. Коли у вас є таблиці, і ви хочете набори, ви перетворюєте таблиці на набори, використовуючи елемент набору як ключ і trueяк значення. +1 до інтер’єру.


2

Я не можу придумати іншого способу порівняння значень, але якщо ви використовуєте елемент набору як ключ, ви можете встановити значення будь-що, крім нуля. Тоді ви отримуєте швидкі пошуки без необхідності шукати всю таблицю.


2

Я знаю, що це стара публікація, але я хотів додати щось для нащадків. Найпростіший спосіб вирішення вашої проблеми - це скласти іншу таблицю, яка має значення для ключа.

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

function addValue(key, value)
    if (value == nil) then
        removeKey(key)
        return
    end
    _primaryTable[key] = value
    _secodaryTable[value] = key
end

function removeKey(key)
    local value = _primaryTable[key]
    if (value == nil) then
        return
    end
    _primaryTable[key] = nil
    _secondaryTable[value] = nil
end

function getValue(key)
    return _primaryTable[key]
end

function containsValue(value)
    return _secondaryTable[value] ~= nil
end

Потім ви можете надіслати запит новій таблиці, щоб перевірити, чи є в ньому ключ 'елемент'. Це запобігає необхідності переглядати всі значення іншої таблиці.

Якщо виявляється, що ви насправді не можете використовувати елемент як ключ, оскільки це не рядок, наприклад, додайте контрольну суму або, tostringнаприклад, на нього, а потім використовуйте це як ключ.

Чому ви хочете це зробити? Якщо ваші таблиці дуже великі, кількість часу для перебору кожного елемента буде значним, що заважає робити це дуже часто. Додаткові накладні витрати на пам’ять будуть відносно невеликими, оскільки вони будуть зберігати 2 вказівники на той самий об’єкт, а не 2 копії того самого об’єкта. Якщо ваші таблиці дуже маленькі, то це матиме набагато менше значення, адже, можливо, навіть швидше буде виконати ітерацію, ніж мати інший пошук на карті.

Однак формулювання запитання настійно наводить на думку, що у вас є велика кількість предметів, з якими потрібно мати справу.


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

1
Крім того, ".key" слід замінити на "[ключ]" скрізь у цьому коді (те саме з "значенням")
Njol,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.