2010-02-17 4 views
74

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

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

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

+2

Что означает обозначение _, обозначение? – Martin

+18

Это просто переменная «мусор» с именем '_'. 'pairs()' возвращает 'key, value', но в этом примере мне нужно только значение. Это своего рода соглашение (принятое в книге «Программирование в Lua» http://www.lua.org/pil/index.html), чтобы использовать эту переменную '_' для хранения вещей, которые вам не нужны. – Wookai

ответ

91

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

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 

Там в более полнофункциональный пример here.

+12

Анонимный пользователь предложил следующее исправление для вашего кода: если значение в наборе с указанным ключом FALSE, функция setContains() возвращает false, хотя в таблице указан указанный ключ. строка «return set [key] ~ = nil» исправляет эту ошибку. – oers

2

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

22

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

0

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

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

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

+0

Хорошее объяснение, но на самом деле ничего не добавляет к обсуждению. Вероятно, было бы лучшей идеей отредактировать ответ interjay. – bcdan

+0

Кроме того, '.key' должен быть заменен на «[ключ]» везде в этом коде (то же самое с «значением») – Njol

 Смежные вопросы

  • Нет связанных вопросов^_^