Как проверить, содержит ли таблица элемент в Lua?

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

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

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

Ответ 1

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

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

Здесь представлен более полнофункциональный пример .

Ответ 2

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

Ответ 3

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

Ответ 4

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

то есть. у вас есть 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 копии одного и того же объекта. Если ваши таблицы очень маленькие, то это будет иметь гораздо меньшее значение, поскольку на самом деле итерация может быть даже быстрее, чем поиск другой карты.

Однако формулировка вопроса настоятельно рекомендует вам иметь дело с большим количеством предметов.