How to check if two tables(objects) have the same value in Lua

后端 未结 6 1616
粉色の甜心
粉色の甜心 2021-01-04 02:00

I wanna check if two tables have the same value in Lua, but didn\'t find the way.

I use the operator ==, it seems just to check the same objects, but no

6条回答
  •  长情又很酷
    2021-01-04 02:56

    I offer some improvements for Rutrus solution.

    function equals(o1, o2, ignore_mt)
        if o1 == o2 then return true end
        local o1Type = type(o1)
        local o2Type = type(o2)
        if o1Type ~= o2Type then return false end
        if o1Type ~= 'table' then return false end
    
        if not ignore_mt then
            local mt1 = getmetatable(o1)
            if mt1 and mt1.__eq then
                --compare using built in method
                return o1 == o2
            end
        end
    
        local keySet = {}
    
        for key1, value1 in pairs(o1) do
            local value2 = o2[key1]
            if value2 == nil or equals(value1, value2, ignore_mt) == false then
                return false
            end
            keySet[key1] = true
        end
    
        for key2, _ in pairs(o2) do
            if not keySet[key2] then return false end
        end
        return true
    end
    

    Be aware that this solution doesn't take into account self references. You may use pequals (below). It's usefull when you have some tricks in your code. But do not use this method for regular checks! It's slower. Also if your object has self reference, you should reanalyze your structure. Self references can be a sign of bad architecture.

    local function internalProtectedEquals(o1, o2, ignore_mt, callList)
        if o1 == o2 then return true end
        local o1Type = type(o1)
        local o2Type = type(o2)
        if o1Type ~= o2Type then return false end
        if o1Type ~= 'table' then return false end
    
        -- add only when objects are tables, cache results
        local oComparisons = callList[o1]
        if not oComparisons then
            oComparisons = {}
            callList[o1] = oComparisons
        end
        -- false means that comparison is in progress
        oComparisons[o2] = false
    
        if not ignore_mt then
            local mt1 = getmetatable(o1)
            if mt1 and mt1.__eq then
                --compare using built in method
                return o1 == o2
            end
        end
    
        local keySet = {}
        for key1, value1 in pairs(o1) do
            local value2 = o2[key1]
            if value2 == nil then return false end
    
            local vComparisons = callList[value1]
            if not vComparisons or vComparisons[value2] == nil then
                if not internalProtectedEquals(value1, value2, ignore_mt, callList) then
                    return false
                end
            end
    
            keySet[key1] = true
        end
    
        for key2, _ in pairs(o2) do
            if not keySet[key2] then
                return false
            end
        end
    
        -- comparison finished - objects are equal do not compare again
        oComparisons[o2] = true
        return true
    end
    
    function pequals(o1, o2, ignore_mt)
        return internalProtectedEquals(o1, o2, ignore_mt, {})
    end
    

    Also you may analyze CompareTables on lua wiki.

提交回复
热议问题