Bienvenidos sean a este post, en el post anterior hemos visto como trabajar con tablas simples pero hoy veremos el otro caso es decir tablas con una topologia generica, tablas con ciclos y subtablas compartidas, y para ello necesitamos otro enfoque porque los constructores no pueden representar tales tablas asi que no las usaremos.
Para representar ciclos necesitamos nombres asi nuestra proxima funcion recibira como argumentos el valor para ser salvado ademas de su nombre, mas aun podemos mantener una pista de los nombres de las tablas salvadas para reusarlos cuando detectemos un ciclo, para este seguimiento se utiliza una tabla extra y tendra tablas como indices y los nombres como los valores asociados, veamos el siguiente codigo:
saved.lua
function serialBasico(o)
if type(o) == "number" then
return tostring(o)
else
return string.format("%q",o)
end
end
function salvar(nombre, valor, salvado)
salvado = salvado or {}
io.write(nombre, " = ")
if type(valor) == "number" or type(valor) == "string" then
io.write(serialBasico(valor), "\n")
elseif type(valor) == "table" then
if salvado[valor] then
io.write(salvado[valor], "\n")
else
salvado[valor] = nombre
io.write("{}\n")
for k,v in pairs(valor) do
k = serialBasico(k)
local fnombre = string.format("%s[%s]", nombre, k)
salvar(fnombre, v, salvado)
end
end
else
error("No se puede salvar a " .. type(valor))
end
end
La primera funcion es una version muy basica de lo que vimos hasta ahora, donde solamente verifica que sea de tipo number y en caso de ser cierto lo convierte a cadena, y en caso contrario asumimos que es de tipo cadena y usamos a string.format como hasta ahora, la siguiente funcion hace todo el trabajo pesado, en este caso tendremos tres argumentos: nombre, valor y salvado (este se encargara de hacer el seguimiento de las tablas salvadas), usara al salvado informado y en caso de no existir crea una, muestra en pantalla a nombre, luego chequea si el tipo de valor coincide con number o string y lo manda a la funcion anterior, si no es asi chequea si es igual a table donde primero verifica si existe en salvado la posicion almacenada en valor y en caso de ser cierto lo escribe en pantalla, de lo contrario crear esta nueva posicion y le asigna a nombre, muestra en pantalla la creacion de tabla, para luego por medio de un bucle for crear la nueva tabla y por ultimo la manda a salvar para que se guarde, si ninguno de los casos anteriores se cumplio nos manda un mensaje de error, la unica restricción con este código es que las claves (keys) pueden ser unicamente numeros o cadenas, este codigo puede ser guardado en un archivo o ser utilizado directamente en el interprete para una mejor visualizacion lo usare en un archivo, vamos a crear la siguiente tabla con un ciclo y una subtabla compartida:
> a = { x=1, y=2; {3,4,5} } // La tabla original
> a[2] = a // el ciclo
> a.z = a[1] // subtabla compartida
Para nuestro siguiente paso cargaremos al archivo saved.lua y llamaremos a salvar de la siguiente forma:
> dofile("saved.lua")
> salvar("a",a)
Esto nos generara la siguiente salida:
a = {}
a[1] = {}
a[1][1] = 3
a[1][2] = 4
a[1][3] = 5
a[2] = a
a["z"] = a[1]
a["x"] = 1
a["y"] = 2
El orden de estas asignaciones puede variar porque depende de la transversal de la tabla, sin embargo el algoritmo nos asegura que cualquier nodo previo necesario en una nueva definicion este definida, en el caso de querer salvar varios valores con partes compartidas podemos hacer las llamadas a salvar con la misma tabla salvada, veamos el siguiente caso:
> a = {{"uno","dos"}, 3}
> b = { k = a[1]}
Y si nosotros llamamos a salvar de la siguiente manera:
> do
>> salvar("a",a)
>> salvar("b",b)
>> end
Al ejecutarlo de maneras independientes no obtendremos partes en comun como se ve en la salida:
a[1] = {}
a[1][1] = "uno"
a[1][2] = "dos"
a[2] = 3
b = {}
b["k"] = {}
b["k"][1] = "uno"
b["k"][2] = "dos"
Sin embargo si usamos la misma tabla de salvado para ambas llamadas a salvar como se ve a continuacion:
> do
>> local t = {}
>> salvar("a",a,t)
>> salvar("b",b,t)
>> end
Al ejecutarlo obtendremos la siguiente salida:
a = {}
a[1] = {}
a[1][1] = "uno"
a[1][2] = "dos"
a[2] = 3
b = {}
b["k"] = a[1]
Como es usual en Lua hay muchas alternativas entre las cuales destaca la de poder salvar un valor sin darle un nombre global, en su lugar el chunk crea un valor local y lo devuelve, tambien podemos manejar funciones que construyen una tabla auxiliar que asocia cada funcion a su nombre, etc.
En resumen, hoy hemos completado lo visto anteriormente como es la posibilidad de crear tablas con subtablas y ciclos, hemos visto su sintaxis, su estructura y una forma muy general de poder ser utilizada, espero les haya sido util sigueme en Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Tambien podes donar
Es para mantenimiento del sitio, gracias!
$1.00