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.

Anuncios

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:

Anuncios
> 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
Anuncios

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:

Anuncios
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.

Anuncios

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