【问题标题】:Differences between two tables in LuaLua中两个表的区别
【发布时间】:2020-12-06 01:48:38
【问题描述】:

我在 lua 中有两个表(在生产中,a 有 18 个元素,b 有 8 个):

local a = {1,2,3,4,5,6}
local b = {3,5,7,8,9}

我需要返回 'a',省略 'b' 中的任何常见元素 -- {1,2,4,6} 类似于 ruby​​ 命令 a-b(如果 a 和 b 是数组)。

我能想到的最好的 lua 逻辑是:

local function find(a, tbl)
    for _,a_ in ipairs(tbl) do if a_==a then return true end end
end

function difference(a, b)
   local ret = {}
   for _,a_ in ipairs(a) do
   if not find(a_,b) then table.insert(ret, a_) end
end

return ret
end

local a = {1,2,3,4,5,6}
local b = {3,5,7,8,9}

local temp = {}
temp = difference(a,b)

print(temp[1],temp[2],temp[3],temp[4])

我需要快速遍历这些表格比较(生产中每秒最少 10K 次)。有没有更清洁的方法来做到这一点?

======

这是 redis 服务器端脚本的一部分,我必须保护我的 Redis CPU。在干净的 Lua 进程之外,我还有另外两个选择:

1.创建两个 redis 临时键,然后运行 ​​sinter 以获得 42 的 big(O)

  • 18 悲伤(一)
  • 8 悲伤(b)
  • 16烧结(a,b)

2.将a和b都返回给ruby做数组比较并返回结果。

  • 每秒数千个连接的后端和四分之一的网络成本将消耗资源。

【问题讨论】:

  • 您是否可以控制如何定义表 ab
  • 在某种程度上是的。思维定势?

标签: optimization lua redis server-side


【解决方案1】:

试试这个:

function difference(a, b)
    local aa = {}
    for k,v in pairs(a) do aa[v]=true end
    for k,v in pairs(b) do aa[v]=nil end
    local ret = {}
    local n = 0
    for k,v in pairs(a) do
        if aa[v] then n=n+1 ret[n]=v end
    end
    return ret
end

【讨论】:

  • 我在lua.org/cgi-bin/demo 上做了一个简单的基准测试。在 100K 循环中,您的代码需要 0.22 秒,我的需要 0.26 秒,并且随着元素数量的增加,差距会扩大。
  • @tjrburgess,搜索表不是 Lua 方式。无论如何,您的算法是 O(mn),其中 m 和 n 是表格的大小。我的是 O(m+n) 但使用更多内存。与小桌子无关
【解决方案2】:

你可以这样做(未经测试):

function difference(a, b)
    local ai = {}
    local r = {}
    for k,v in pairs(a) do r[k] = v; ai[v]=true end
    for k,v in pairs(b) do 
        if ai[v]~=nil then   r[k] = nil   end
    end
    return r
end

如果你可以修改a那就更短了:

function remove(a, b)
    local ai = {}
    for k,v in pairs(a) do ai[v]=true end
    for k,v in pairs(b) do 
        if ai[v]~=nil then   a[k] = nil   end
    return r
end

如果您的表已排序,您还可以同时对两个表进行并行扫描,类似于以下伪代码:

function diff(a, b)
    Item = front of a
    Diff = front of b
    While Item and Diff
       If Item < Diff then 
           Item is next of a
       Else if Item == Diff then 
           remove Item from a
           Item = next of a
           Diff = next of b
       Else         # else Item > Diff
           Diff = next of b

这不使用任何额外的表格。即使您想要新表而不是就地差异,也只有一个新表。我想知道它与哈希表方法(remove)相比如何。

请注意,循环多少次并不重要,如果ab 很小,那么它们与您的算法之间不会有太大区别。 ab 中至少需要 100 个项目,甚至可能需要 1000 个。

【讨论】:

  • 在我的标准 MacBook Pro 上进行一些基本的台架测试表明,与其他版本相比,这种差异功能的运行速度提高了约 5%。 remove 函数的运行速度提高了约 5%。
【解决方案3】:

也许是这样的:

function get_diff (t1, t2) 
    local diff = {}
    local bool = false
    for i, v in pairs (t1) do
        if t2 and type (v) == "table" then
            local deep_diff = get_diff (t1[i], t2[i]) 
            if deep_diff then
                diff[i] = deep_diff
                bool = true
            end
        elseif t2 then
            if not (t1[i] == t2[i]) then
                diff[i] = t1[i] .. ' -- not [' .. t2[i] .. ']'
                bool = true
            end
        else 
            diff[i] = t1[i]
            bool = true
        end
    end
    
    if bool then
        return diff
    end
end

local t1 = {1, 2, 3, {1, 2, 3}}
local t2 = {1, 2, 3, {1, 2, 4}}
local diff = get_diff (t1, t2) 

结果:

diff = {
  nil,
  nil,
  nil,
  {
    [3] = "3 -- not [4]"
  }
}

【讨论】:

  • 请解释你的代码是做什么的以及它是怎么做的。
  • 该函数搜索两个表之间的差异并返回具有相同键的不同的字符串。因此,如果您有两个表 t1 和 t2,那么它会打印每个表层上的值之间的差异。所以 diff[4][3] 在 t1[4][3] 和 t2[4][3] 之间有区别,就像刺一样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-11
  • 2014-01-13
  • 1970-01-01
  • 1970-01-01
  • 2016-05-29
  • 2016-08-15
  • 1970-01-01
相关资源
最近更新 更多