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

98

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

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

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

Wookai
источник
3
что означает обозначение _?
Мартин,
24
Это просто "мусорная" переменная с именем _. pairs()возвращается key, value, но в этом примере мне нужно только значение. Это своего рода соглашение (принятое в книге «Программирование на Lua» lua.org/pil/index.html ) использовать эту _переменную для хранения вещей, которые вам не нужны.
Wookai
Я также видел соглашение об именовании «мусорных» переменных, _используемое в Python и JavaScript.
iono

Ответы:

117

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

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

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

Джоэл
источник
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' следует заменить на '[key]' повсюду в этом коде (то же самое, что и 'value')
Нджол