Question

If I have a list of items like this:

local items = { "apple", "orange", "pear", "banana" }

how do I check if "orange" is in this list?

In Python I could do:

if "orange" in items:
    # do something

Is there an equivalent in Lua?

Was it helpful?

Solution

You could use something like a set from Programming in Lua:

function Set (list)
  local set = {}
  for _, l in ipairs(list) do set[l] = true end
  return set
end

Then you could put your list in the Set and test for membership:

local items = Set { "apple", "orange", "pear", "banana" }

if items["orange"] then
  -- do something
end

Or you could iterate over the list directly:

local items = { "apple", "orange", "pear", "banana" }

for _,v in pairs(items) do
  if v == "orange" then
    -- do something
    break
  end
end

OTHER TIPS

Use the following representation instead:

local items = { apple=true, orange=true, pear=true, banana=true }
if items.apple then
    ...
end

You're seeing firsthand one of the cons of Lua having only one data structure---you have to roll your own. If you stick with Lua you will gradually accumulate a library of functions that manipulate tables in the way you like to do things. My library includes a list-to-set conversion and a higher-order list-searching function:

function table.set(t) -- set of list
  local u = { }
  for _, v in ipairs(t) do u[v] = true end
  return u
end

function table.find(f, l) -- find element v of l satisfying f(v)
  for _, v in ipairs(l) do
    if f(v) then
      return v
    end
  end
  return nil
end

Lua tables are more closely analogs of Python dictionaries rather than lists. The table you have create is essentially a 1-based indexed array of strings. Use any standard search algorithm to find out if a value is in the array. Another approach would be to store the values as table keys instead as shown in the set implementation of Jon Ericson's post.

function valid(data, array)
 local valid = {}
 for i = 1, #array do
  valid[array[i]] = true
 end
 if valid[data] then
  return false
 else
  return true
 end
end

Here's the function I use for checking if data is in an array.

Sort of solution using metatable...

local function preparetable(t)
 setmetatable(t,{__newindex=function(self,k,v) rawset(self,v,true) end})
end

local workingtable={}
preparetable(workingtable)
table.insert(workingtable,123)
table.insert(workingtable,456)

if workingtable[456] then
...
end

This is a swiss-armyknife function you can use:

function table.find(t, val, recursive, metatables, keys, returnBool)
    if (type(t) ~= "table") then
        return nil
    end

    local checked = {}
    local _findInTable
    local _checkValue
    _checkValue = function(v)
        if (not checked[v]) then
            if (v == val) then
                return v
            end
            if (recursive and type(v) == "table") then
                local r = _findInTable(v)
                if (r ~= nil) then
                    return r
                end
            end
            if (metatables) then
                local r = _checkValue(getmetatable(v))
                if (r ~= nil) then
                    return r
                end
            end
            checked[v] = true
        end
        return nil
    end
    _findInTable = function(t)
        for k,v in pairs(t) do
            local r = _checkValue(t, v)
            if (r ~= nil) then
                return r
            end
            if (keys) then
                r = _checkValue(t, k)
                if (r ~= nil) then
                    return r
                end
            end
        end
        return nil
    end

    local r = _findInTable(t)
    if (returnBool) then
        return r ~= nil
    end
    return r
end

You can use it to check if a value exists:

local myFruit = "apple"
if (table.find({"apple", "pear", "berry"}, myFruit)) then
    print(table.find({"apple", "pear", "berry"}, myFruit)) -- 1

You can use it to find the key:

local fruits = {
    apple = {color="red"},
    pear = {color="green"},
}
local myFruit = fruits.apple
local fruitName = table.find(fruits, myFruit)
print(fruitName) -- "apple"

I hope the recursive parameter speaks for itself.

The metatables parameter allows you to search metatables as well.

The keys parameter makes the function look for keys in the list. Of course that would be useless in Lua (you can just do fruits[key]) but together with recursive and metatables, it becomes handy.

The returnBool parameter is a safe-guard for when you have tables that have false as a key in a table (Yes that's possible: fruits = {false="apple"})

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top