11
votes

Utilisez le contenu d'une table comme clé

Y a-t-il un moyen facile de créer une collection de dictionnaire, c'est-à-dire

    Les tables
  1. peuvent être utilisées comme clés Les tables
  2. avec le même contenu sont considérées comme équivalentes (au lieu de la comparaison du pointeur par défaut)

    E.g. Après xxx

    t [k2] devrait évaluer à vrai .
    Également t lui-même doit être utilisable comme une clé de la même manière.

    existe-t-il un moyen de le faire sans

    1. réémayer les tables de hachage
    2. Conversion k1 et k2 à cordes? (C'est ce que je fais actuellement.)
lua

0 commentaires

5 Réponses :


1
votes

Vous pouvez mettre en œuvre et définir la méthode __eq dans la métabilité des deux tables.

k1 = {'a','b','c'}
k2 = {'a','b','c'}
mt1={__eq=function(a,b)
   for k,v in pairs(a) do
      if b[k]~=v then return false end
   end
   for k,v in pairs(b) do
      if a[k]~=v then return false end
   end
   return true
end
}
setmetatable(k1,mt1)
setmetatable(k2,mt1)

assert(k1==k2,"Table comparison failed")

function newDict(orig)
    if orig then
        return orig
    else
        local mt2={}
        local lookup ={} -- lookup table as upvalue to the metamethods
        mt2.__newindex = function(t,k,v) -- Registering a new table
            if type(k)~="table" then return end
            if v then   -- v ~= false
                local found
                for idx,val in pairs(lookup) do
                    if k==val then
                        found=1
                        break
                    end -- If already seen, skip.
                end
                if not found then
                    lookup[#lookup+1]=k -- not seen before, add
                end 
            else -- v == false or nil
                local to_erase
                for idx,val in pairs(lookup) do -- Assume there is only one match in the dict.
                    if k==val then
                        lookup[k]=nil
                        break
                    end --don't continue after this, next will be confused.
                end
            end         
        end

        mt2.__index = function(t,k) -- looking up a table
            for idx,val in pairs(lookup) do
                if k==val then 
                    return true
                end
            end
            return false
        end
        return setmetatable({},mt2)
    end
end

t1 = newDict()
t2 = newDict()

k1={1,2,3}
k2={"a"}
k3={"z","d","f"}

k1b={1,2,3}
k2b={"a"}
k3b={"z","d","f"}

setmetatable(k1,mt1)
setmetatable(k2,mt1)
setmetatable(k3,mt1)

setmetatable(k1b,mt1)
setmetatable(k2b,mt1)
setmetatable(k3b,mt1)

-- Test multiple entries in 1 dict
t1[k1]=true
t1[k2]=true
assert(t1[k1b],"t1[k1b] did not return true")
assert(t1[k2b],"t1[k2b] did not return true")
-- Test confusion between 2 dicts
t2[k3]=true
assert(not t1[k3b],"t1[k3b] did return true")
assert(not t2[k1b],"t2[k1b] did return true")


4 commentaires

Je vois que cela fait k1 == k2 vrai, mais ce n'est pas le même que t [k1] == t [k2]


T = SETMETATINABLE ({}, {__ index = fonction (t, k) retour k extrémité}) fait que cela se produit pour vous.


C'est un piratage qui fonctionnera s'il n'y a qu'un seul tableau t par processus. En fait, j'ai trois tables de ce type qui doivent être indépendamment des tables vers d'autres valeurs.


Totalement changé pour correspondre aux spécifications exactement. Des choses que vous pourriez envisager de changer: le fonctionnement de l'égalité des tables; raccourci pour les tables qui sont littéralement les mêmes (même pointeur); Métaditable jonglant pour garder les métables d'origine des tables comparées.



0
votes

Cette section ("Les clés sont des références") indique que les touches sont des références aux objets afin d'utiliser Un tableau identique comme dans votre exemple ne fonctionnera pas. Je pense que la façon dont vous faites en train de le faire peut être le meilleur moyen, mais je pourrais me tromper.


0 commentaires

0
votes

Si vous pouvez supporter une dépendance de la bibliothèque, vous pouvez utiliser quelque chose comme PenLight qui semble offrir des ensembles http://penlight.luaforge.net/#t10 .


1 commentaires

Afaict que la bibliothèque ne fait pas ce que je veux, c'est-à-dire autoriser deux tables (ou ensembles ou cartes, etc.) à traiter comme des touches équivalentes . Comme les bibliothèques vont, je pense Sano est un meilleur match (il fait ce que je veux pour " tuples "mais pas des ensembles / mappages arbitraires, encore.)



3
votes

Si les tables à utiliser à mesure que les touches sont corrigées et que leur contenu ne change pas, vous pouvez créer un Digest SHA2 sur la demande dans un Newindex métaméthod pour t et utilisez le Digestez comme la clé réelle. Le digest serait mis en cache dans une autre table indexée par les tables réelles.


0 commentaires

4
votes

Serializing Les deux tables dans Strings sont la solution Roberto Ierusalimschy (chef architecte de Lua) recommande d'indexer par contenu dans Programmation de Lua 2nd Edition . .

Si toutes vos tables de clé sont des tableaux de chaînes (sans nulls incorporés), cela peut être effectué rapidement avec table.concat (t, '\ 0') . (Évidemment, votre table devra être trié si Vous voulez une identité indépendante index.)


2 commentaires

Est le résultat de table.concat trié par les touches?


Vous voulez dire "si toutes vos valeurs sont des chaînes et des clés sont des entiers consécutifs à partir de 1 ...." table.concat ne fait rien avec le non-tableau partie d'une table.