Как проверить, содержит ли таблица элемент в Lua? - PullRequest
88 голосов
/ 17 февраля 2010

Есть ли способ проверки, содержит ли таблица значение? У меня есть своя (наивная) функция, но мне было интересно, существует ли для этого что-то «официальное»? Или что-то более эффективное ...

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

Кстати, основная причина, по которой я использую эти функции, состоит в том, чтобы использовать таблицы как наборы, то есть без дублирующих элементов. Есть ли что-то еще, что я мог бы использовать?

Ответы [ 4 ]

111 голосов
/ 17 февраля 2010

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

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

Более полнофункциональный пример здесь .

24 голосов
/ 17 февраля 2010

Учитывая ваше представление, ваша функция настолько эффективна, насколько это возможно. Конечно, как отмечали другие (и практикуется на языках старше Lua), решение вашей реальной проблемы - изменить представление. Когда у вас есть таблицы и вы хотите наборы, вы превращаете таблицы в наборы, используя элемент набора в качестве ключа и true в качестве значения. +1 к междурядью.

2 голосов
/ 02 сентября 2013

Я знаю, что это старый пост, но я хотел добавить кое-что для потомков. Простой способ справиться с возникшей проблемой - создать другую таблицу, имеющую значение для ключа.

т. у вас есть 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

Затем вы можете запросить новую таблицу, чтобы узнать, имеет ли она ключ 'element'. Это избавляет от необходимости перебирать каждое значение другой таблицы.

Если окажется, что вы не можете использовать «элемент» в качестве ключа, потому что это не строка, например, то добавьте к ней контрольную сумму или «toString», например, а затем используйте ее в качестве ключа .

Почему ты хочешь это сделать? Если ваши таблицы очень большие, количество времени для итерации каждого элемента будет значительным, что не позволит вам делать это очень часто. Дополнительная нагрузка на память будет относительно небольшой, поскольку в ней будет храниться 2 указателя на один и тот же объект, а не 2 копии одного и того же объекта. Если ваши таблицы очень маленькие, то это будет иметь гораздо меньшее значение, так как, возможно, итерация будет быстрее, чем поиск другой карты.

Формулировка вопроса, однако, настоятельно предполагает, что у вас есть большое количество предметов для работы.

2 голосов
/ 17 февраля 2010

Я не могу придумать другой способ сравнения значений, но если вы используете элемент набора в качестве ключа, вы можете установить значение на любое значение, кроме nil. Тогда вы получите быстрый поиск без необходимости поиска по всей таблице.

...