在Lua列表中搜索项目

69
如果我有一个像这样的项目列表:
local items = { "apple", "orange", "pear", "banana" }

我该如何检查这个列表中是否包含"orange"?

在Python中,我可以这样做:

if "orange" in items:
    # do something

Lua有相应的功能吗?

12个回答

93

你可以使用类似于《Lua程序设计》中的集合方式:

function Set (list)
  local set = {}
  for _, l in ipairs(list) do set[l] = true end
  return set
end
然后,您可以将您的列表放入Set中并测试成员资格:
local items = Set { "apple", "orange", "pear", "banana" }

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

或者您可以直接遍历该列表:

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

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

37
请使用以下表示方式代替:

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

4
这是在Lua中以纯数学意义上创建一组事物的最佳方法。太棒了!然而,由于Lua没有顺序的概念,如果列表的顺序很重要,它并不能回答“在Lua列表中搜索一个项”的一般性问题。 - Mark
这感觉更加优雅。我刚用它创建了一个看起来像{thingIAmLookingFor:true, secondThingIAmLookingFor:true}的表格。 - stiller_leser
1
这是一个不错的答案,但它并没有解决问题的一般性问题:对于任意字符串列表该怎么办?在Python中等价的if "orange" in items并不需要构建您自己的专门列表。有没有一种Lua方法可以接受任何字符串列表并以这种方式重建它? - Zim
@CalculatorFeline 一些键(包括数字、空格、重音符号等)需要使用括号表示法。例如:local items = { [42]=true, ['foo bar']=true, ['éà']=true }。实际上,没有括号的表示法是一种语法糖(在Lua中经常出现)。您可能会对Tables Tutorial感兴趣。 - Gras Double

21

您正在第一时间看到Lua只有一种数据结构的缺点之一,即您必须自己编写。如果您坚持使用Lua,您将逐渐积累一个库,其中包含以您喜欢的方式操作表格的函数。我的库包括列表转换为集合和高阶列表搜索函数:

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

这仍然适用吗?只是一个建议:更具描述性的变量名称会对许多查看者有所帮助。 - LabGecko
f代表函数,l代表列表,v代表值 - Norman Ramsey

4

你可以按照自己的方式编写代码,但是直接遍历列表比使用pairs()或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' )

发现了橙色
未发现车辆


3
这是一个你可以使用的瑞士军刀函数:

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

你可以使用它来检查值是否存在:
local myFruit = "apple"
if (table.find({"apple", "pear", "berry"}, myFruit)) then
    print(table.find({"apple", "pear", "berry"}, myFruit)) -- 1

你可以使用它来查找密钥:
local fruits = {
    apple = {color="red"},
    pear = {color="green"},
}
local myFruit = fruits.apple
local fruitName = table.find(fruits, myFruit)
print(fruitName) -- "apple"

我希望“recursive”参数可以自解释。
“metatables”参数允许您搜索元表。
“keys”参数使函数在列表中查找键。当然,在Lua中这是无用的(您只需执行“fruits[key]”),但与“recursive”和“metatables”一起使用时,它变得方便。
“returnBool”参数是一个安全保护措施,用于处理具有“false”作为键的表(是的,这是可能的:“fruits = {false =“apple”}”)。

3
Lua表格更类似于Python字典而不是列表。您创建的表格本质上是一个基于1的索引字符串数组。使用任何标准搜索算法来查找数组中是否存在某个值。另一种方法是将值存储为表键,而不是像Jon Ericson帖子中的set实现所示的那样。

2
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

这是我用来检查数据是否在数组中的函数。

1
以下表示方式可以使用:
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

相关输出:
apple is a true value.
red is a false value.

您也可以使用以下代码来检查布尔值的有效性:
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

输出结果为:

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

请查看表格教程获取更多信息。


1
一种使用元表的解决方案...
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

这与以下代码有何不同?workingtable[123] = true workingtable[456] = true if workingtable[456] then ... end``` - Luc Bloom

0
可以使用一个简单的函数来实现以下功能:
  • 如果在表中未找到该项,则返回nil
  • 如果在表中找到该项,则返回该项的索引
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"))

以上代码的输出将会是:
3
nil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接