Search for an item in a Lua list

ListLuaLua Table

List Problem Overview


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?

List Solutions


Solution 1 - List

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

Solution 2 - List

Use the following representation instead:

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

Solution 3 - List

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

Solution 4 - List

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.

Solution 5 - List

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"})

Solution 6 - List

Write it however you want, but it's faster to iterate directly over the list, than to generate pairs() or ipairs()

#! /usr/bin/env lua

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

local function locate( table, value )
    for i = 1, #table do
        if table[i] == value then print( value ..' found' ) return true end
    end
    print( value ..' not found' ) return false
end

locate( items, 'orange' )
locate( items, 'car' )

orange found
car not found

Solution 7 - List

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.

Solution 8 - List

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

Solution 9 - List

function table.find(t,value)
    if t and type(t)=="table" and value then
        for _, v in ipairs (t) do
	        if v == value then
		        return true;
	        end
        end
        return false;
    end
    return false;
end

Solution 10 - List

you can use this solution:

items = { 'a', 'b' }
for k,v in pairs(items) do 
 if v == 'a' then 
  --do something
 else 
  --do something
 end
end

or

items = {'a', 'b'}
for k,v in pairs(items) do 
  while v do
    if v == 'a' then 
      return found
    else 
      break
    end
  end 
 end 
return nothing

Solution 11 - List

A simple function can be used that :

  • returns nil, if the item is not found in table
  • returns index of item, if item is found in table
local items = { "apple", "orange", "pear", "banana" }

local function search_value (tbl, val)
    for i = 1, #tbl do
        if tbl[i] == val then
            return i
        end
    end
    return nil
end

print(search_value(items, "pear"))
print(search_value(items, "cherry"))

output of above code would be

3
nil

Solution 12 - List

The following representation can be used:

local items = {
    ["apple"]=true, ["orange"]=true, ["pear"]=true, ["banana"]=true
}

if items["apple"] then print("apple is a true value.") end
if not items["red"] then print("red is a false value.") end

Related output:

apple is a true value.
red is a false value.

You can also use the following code to check boolean validity:

local items = {
    ["apple"]=true, ["orange"]=true, ["pear"]=true, ["banana"]=true,
    ["red"]=false, ["blue"]=false, ["green"]=false
}

if items["yellow"] == nil then print("yellow is an inappropriate value.") end
if items["apple"] then print("apple is a true value.") end
if not items["red"] then print("red is a false value.") end

The output is:

yellow is an inappropriate value.
apple is a true value.
red is a false value.

Check Tables Tutorial for additional information.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJayView Question on Stackoverflow
Solution 1 - ListJon EricsonView Answer on Stackoverflow
Solution 2 - ListfsanbrView Answer on Stackoverflow
Solution 3 - ListNorman RamseyView Answer on Stackoverflow
Solution 4 - ListJudge MaygardenView Answer on Stackoverflow
Solution 5 - ListLuc BloomView Answer on Stackoverflow
Solution 6 - ListDoyousketch2View Answer on Stackoverflow
Solution 7 - ListKingofGamesYamiView Answer on Stackoverflow
Solution 8 - ListKonstantin ArtemievView Answer on Stackoverflow
Solution 9 - ListnxFairlywellView Answer on Stackoverflow
Solution 10 - ListSetareh NazeriView Answer on Stackoverflow
Solution 11 - ListRudra LadView Answer on Stackoverflow
Solution 12 - ListircamaView Answer on Stackoverflow