PDA

Ver la Versión Completa : [ ARTICULO ] Uso de variables y matrices en Tasker


cace0353
19/04/14, 17:33:40
Desde el primer dia que me metí con Tasker para probar "cosas", leí en los tutoriales que Tasker no trabajaba con matrices de datos sino que empleaba "falsas matrices". Esto me dejó un poco descolocado...

Luego, con el desarrollo de un par de Proyectos que incluian y manejaban bases de datos, he visto que, una vez le has cogido el tranquillo y has leido Proyectos tan elaborados y complejos como, por ejemplo, el de mlsir (Whatsapp sin manos), realmente SI que podemos llamarlas matrices. Construidas de otro modo, de acuerdo, pero matrices al fin y al cabo.

De todas formas me viene a la cabeza un chiste del recordado Eugenio que decia, después del Ya sabeis aquel..:
Se encuentran dos amigos y uno le dice al otro:
¿Como lo haces para conservarte tan joven?
Pues no discutiendo con nadie!
Por eso no será...
Bueno, pues no será por eso...

Así que, si quereis, podeis llamarlas Matrices, Arrays o Arreglos (así no, por favor!)
Por mi parte, como estoy acostumbrado a llamarlas Matrices, voy a usar este nombre a lo largo de este trabajo. Además tiene otra acepción en el diccionario: "Entidad generadora de otras" que se ajusta exactamente a lo que son como vereis más adelante.

OBJETIVO DEL TRABAJO

El objetivo fijado es allanar la comprensión de conceptos básicos sobre las variables (para los que empiezan o no se atreven con ellas) y facilitar estructuras simples de creación, manipulación y procesamiento de matrices de datos con ejemplos ilustrativos. El disponer de un almacén de datos es esencial para muchos de los programas que se nos ocurren. Este trabajo pretende facilitar el acceso a este recurso básico de la programación.

DEFINICIONES

Voy a establecer de entrada algunas definiciones:

VARIABLE

Nombre asignado a un espacio en la memoria del dispositivo para guardar un dato que va a ser usado en alguna fase del programa o Proyecto.

Se identifica en Tasker porque va precedido por el símbolo %. Escrito con alguna letra en mayúsculas (%Variable, o %variaBle) tiene el carácter de variable global y puede recuperarse su contenido desde cualquier tarea del proyecto o de otros proyectos dentro de Tasker. Se almacena como datos del programa.

Si su nombre no contiene ninguna mayúscula (p.e. %temporal) es una variable local de la tarea en donde se le ha asignado un valor pero, al salir de esta tarea, se pierde el contenido y, incluso, el nombre de la variable.

El valor guardado en las variables de los dos tipos anteriores (variables de usuario) puede ser un número entero, un número decimal, una cadena de caracteres o una mezcla de todo lo anterior. En el límite, podriamos guardar toda la novela "El ingenioso hidalgo don Quijote de la Mancha" en una sola variable que podriamos llamar, acertadamente, como %Quijote. A este respecto es recomendable que el nombre de la variable, si se puede, indique de alguna manera su contenido.

Variable de Sistema es una variable que proporciona Tasker y en la que se guarda algún valor que facilita el propio sistema Android. Por ejemplo $DATE contiene la fecha de hoy, %TIME la hora actual, %LOC las coordenadas obtenidas con GPS, etc. Podemos usarlas y operar con ellas pero generalmente, con algunas excepciones, no podremos modificarlas.

Una variable de usuario (global o local), como se ha dicho, puede contener cifras, letras, caracteres sueltos, frases completas y una mezcla de todo. Un ejemplo: creamos una variable que llamaré %fulano y en la que, mediante una acción Establecer Variable escribo: Martínez|Pérez|Luis|12-03-1975|Barcelona. De momento tengo UN sólo dato, una variable que contiene distintas "cosas"...

MATRIZ LINEAL

Tasker nos facilita un instrumento para extraer los datos de variables que, como %fulano, se han "preparado" convenientemente para convertirlas en lo que llamaremos una Matriz lineal. Esta acción "mágica" es "Separar Variable" y lo que hace es dividir el contenido de la variable de entrada (%fulano) mediante un carácter especial: el Separador (aquí el "|"). El resultado de la extracción son (ahora si) variables independientes que llamaremos "hijas" de %fulano. Estas variables hijas podremos identificarlas y operar con ellas separadamente como variables que son. El número de "hijas" será igual al número de separadores + 1.

¿Y como nos referiremos a ellas o recuperaremos su valor? pues por su índice dentro de la matriz lineal: %fulano(1)= Martínez, %fulano(2)=Pérez, %fulano(3)=Luis, %fulano(4)=12-03-1975 y %fulano(%)=Barcelona o más simplemente: %fulano1, %fulano2, %fulano3, %fulano4 y %fulano5.

Como antes y como variables que son, pueden ser globales (alguna letra mayúscula) o locales (todo en minúscula) según la "vida" y uso que deban tener. Si la variable inicial es global las hijas seran variables globales. Si es local las hijas serán locales.

En resumen, podemos concatenar (unir o enlazar) datos de distinto tipo en una sola variable que los contiene (%fulano, en el ejemplo) utilizando un carácter separador distintivo que utilizaremos para recuperarlas.
Al "fabricar" con los datos la variable de inicio elegimos el carácter separador que luego utilizaremos para obtener sus elementos individuales. Evidentemente para este fin eligiremos un carácter que no aparezca en ninguno de los datos, de lo contrario la acción Separar Variable nos podria cortar la variable %fulano por donde no esperamos.
Otra cosa: al separar la variable se pierde el separador utilizado, desaparece.

MATRIZ DE DOS DIMENSIONES

Vamos a escribir en una variable (Establecer Variable) un conjunto de datos (numéricos, alfanuméricos o combinación de ambos) usando DOS caracteres (& $ |! # u otro) separadores.
Ejemplo: Podemos construir una tabla de dos dimensiones (filas y columnas, como en una hoja de Excel) en la variable %Nombres que contiene los siguientes datos: José;Juan;Luisa;Antonio#Juan;Elena;Iñaki#Maria;Ped ro;Regina#Luis;José;Alberto;Maria José;Martina (Atentos: de momento tengo una sola variable con dos tipos de caracteres incrustados ";" y "#")

Mediante la acción "Separar Variable" sobre la variable %Nombres con el separador # obtendremos una matriz (lineal) con quatro variables que serán:
%Nombres1 = José;Juan;Luisa;Antonio
%Nombres2 = Juan;Elena;Iñaki
%Nombres3 = Maria;Pedro;Regina
%Nombres4 = Luis;José;Alberto;Maria José;Martina
(he puesto intencionadamente cantidades diferentes de nombres en cada grupo...)

Si aplicamos de nuevo la acción separar variable sobre la primera de las variables llamadas "hijas" de la matriz: %Nombres1, ahora con el separador ";" obtendremos las variables "nietas":
%Nombres11 = José
%Nombres12 = Juan
%Nombres13 = Luisa
%Nombres14 = Antonio
El índice 11 indica que %Nombres11 es la 1ª hija de la 1ª hija (la 1ªnieta de %Nombres, pues)
El indice 12 indica que %Nombres12 es la 2ª hija de la 1ª hija (la 2ªnieta)...

Igualmente podemos hacerlo sobre %Nombres2 para obtener los valores:
%Nombres21 = Juan
%Nombres22 = Elena
%Nombres23 = Iñaki

Y, de la misma manera, sobre %Nombres3 y %Nombres4
.............
Aquí yo ya me perdía cuando lei la traducción del manual original de Tasker...!
.............

Este procedimiento es el sistema ortodoxo (del manual) pero tiene algunos inconvenientes que complican su comprensión y utilización:
- Si hay más de 9 "hijas", al extraer las "nietas" los índices numéricos se entremezclan (¿ %Nombres123 es la nieta 3 de %Nombres12 o la hija 123 de %Nombres o la nieta 23 de %Nombres1?)
- La variable global %Nombres (antes de separar sus elementos la primera vez para generar la matriz) se mantiene al descomponerla. Así pues, además de la variable original que lo contiene todo, tendremos las hijas y las nietas, todas ellas globales. En resumen: un monton de datos guardados 3 veces en la memoria.
Y si la matriz tiene 3 dimensiones me van a aparecer "biznietas"!

¿Como resuelvo esto?

Una manera muy intuitiva y práctica es mediante el empleo de variables locales y matrices locales. En realidad, pocas veces necesitamos extraer todos los datos de una matriz de dos dimensiones (como almacén de variables), normalmente necesitamos acceder a los datos para consultar uno sólo (nieta) o a los de una sola fila de la tabla (hija).

Para ello expongo el sigüiente

EJEMPLO PRÁCTICO

Supongamos que tenemos un tren con 8 vagones y en cada uno de los cuales hay 50 asientos.

Construimos una variable (%Tren) que contiene, separados por # la lista de los nombres y apellidos de los pasajeros que viajan en cada vagón. Los nombres de los pasajeros los separaré con ;

Esta variable (que no matriz, de momento!) podria escribirse así:
José Pérez;Juan García...;Pedro Matas#Alberto Ruiz; ;......;Luis Gómez;Josefa Antón#Carlos Fuentes;Juan Galdós;...Antonio Durán#Elisa Jiménez;Maria de la Hoz;...#... (Bién, ya lo habeis entendido, no me hagaís inventar más nombres...!)

Fijaros que después de Alberto Ruiz hay un asiento vacio que ha quedado escrito entre separadores así ; ; (no lo pongo para marear la perdiz, los trenes no van siempre llenos!)

PROBLEMA 1: ¿Qué pasajero ocupa el asiento número 2 del vagón 3?

Vamos a copiar el contenido de la Variable global %Tren en una variable local %vagon:
Establecer variable %vagon A %Tren

Y generamos la matriz %vagon:
Separar Variable %vagon separador: #

¿Resultado?: Una matriz local cuyos elementos són la lista de los pasajeros de cada vagón. Así:
%vagon1 contiene José Pérez;Juan García;...;Pedro Matas
%vagon2 contiene Alberto Ruiz; ;......;Luis Gómez;Josefa Antón
%vagon3 contiene Carlos Fuentes;Juan García;...;Antonio Durán
etc...

Podemos extraer los nombres de todos los pasajeros del %vagon3 de esta manera:

Establecer variable %pasajero A %vagon3
Separar variable %pasajero separador ; (Extraemos los nombres de los pasajeros del %vagon3 obteniendo %pasajero1,%pasajero2;%pasajero3...)

El nombre del pasajero número 2 del vagón 3 es Juan García!
Este nombre lo podemos copiar a una variable global %Nombre_pasajero para que pueda ser utilizado en la tarea que requirió quién era el pasajero del asiento nº 2 del 3er vagón .(Podemos devolverlo como variable local, pero de momento lo dejamos aquí. Podeis consultar documentación específica sobre el uso de Tareas y Subtareas en este artículo de Caravantes: http://www.htcmania.com/showthread.php?t=744076)

Recapitulando, hemos superado los dos inconvenientes enunciados anteriormente:
- No hay índices de "hijas" y "nietas" mezclados.
- Usamos variables locales y matrices locales. Por tanto, al finalizar la tarea, se recupera el espacio de memoria que ocupaban. Sólo se mantiene la variable global %Tren y la que hemos creado %Nombre_pasajero que es reutilizable...

Problema: ¿como lo escribimos en Tasker?

Datos: %Tren = Lista de pasajeros del tren separados por ; y con un caracter # separando los vagones.

Busco, como en el ejemplo, el pasajero 2 del vagón 3

Desde la tarea que necesita el nombre ejecutamos la subtarea que nos lo proporcionará y que llamo Nombre Del Pasajero
Acción Ejecutar tarea: Nombre Del Pasajero %par1=2 %par2=3 (%par1 = asiento del pasajero %par2 número del vagón)

La tarea Nombre Del Pasajero será así:

Nombre Del Pasajero (22)
A1: Establecer variable [ Nombre:%vagon A:%Tren Calcular:Apagado Añadir:Apagado ] (copio la variable global %Tren a la variable local %vagon)
A2: Separar variable [ Nombre:%vagon Separador:# Eliminar base:Apagado ]
(genero la matriz %vagon cuyas hijas %vagon1,%vagon2... son las listas de pasajeros de cada vagon)
A3: Establecer variable [ Nombre:%pasajero A:%vagon(%par2) Calcular:Apagado Añadir:Apagado ]
(copio la lista de pasajeros del vagon que me interesa %par2=3 a una variable local %pasajero)
A4: Separar variable [ Nombre:%pasajero Separador:; Eliminar base:Apagado ] (genero la matriz %pasajero cuyas hijas son los nombres de cada pasajero)
A5: Establecer variable [ Nombre:%Nom_pasaj A:%pasajero(%par1) Calcular:Apagado Añadir:Apagado ]
(copio el nombre del pasajero que ocupa el lugar %par1=2 a la variable global %Nom_pasaj que necesita la tarea que me lo ha pedido)
<<H1><font color = green> Filtro para CASOS ESPECIALES>
(etiqueta en color y con caracteres grandes que me indica para que sirve lo que viene a continuación y que... leedlo, se entiende fácil!)
A6: Establecer variable [ Nombre:%Nom_pasaj A:Asiento libre Calcular:Apagado Añadir:Apagado ] Si (if) [ %Nom_pasaj ~ %pas+ ]
A7: Establecer variable [ Nombre:%Nom_pasaj A:Asiento libre Calcular:Apagado Añadir:Apagado ] Si (if) [ %Nom_pasaj !~ ++ ]
A8: Establecer variable [ Nombre:%Nom_pasaj A:No existe el asiento %Asiento Calcular:Apagado Añadir:Apagado ] Si (if) [ %Asiento > 50 ]
A9: Establecer variable [ Nombre:%Nom_pasaj A:No existe el vagon %Vagon Calcular:Apagado Añadir:Apagado ] Si (if) [ %Vagon > 8 ]PROBLEMA 2: ¿Que número de asiento ocupa y en que vagon está el pasajero Josefa Antón?

Datos: %Tren y %Pasajero (Josefa Antón en este caso)

Desde la tarea que necesita el número de asiento y de vagón llamamos a la subtarea que nos lo proporcionará Tarea y que he llamado "Numero De Asiento"

Acción Ejecutar tarea "Numero De Asiento" %par1=%Pasajero %par2=vacio

La tarea Numero De Asiento hará esto, en lenguaje de Tasker y sangrando el texto en los bucles anidados:

Numero De Asiento (64)
A1: Establecer variable [ Nombre:%vagon A:%Tren Calcular:Apagado Añadir:Apagado ]
A2: Separar variable [ Nombre:%vagon Separador:# Eliminar base:Apagado ]
A3: Establecer variable [ Nombre:%cont_vagon A:0 Calcular:Apagado Añadir:Apagado ]
A4: For [ Variable:%pasajeros Ítems:%vagon(:) ]
A5: Sumar a variable [ Nombre:%cont_vagon Valor:1 Módulo (wrap around):0 ]
A6: Establecer variable [ Nombre:%cont_pasaj A:0 Calcular:Apagado Añadir:Apagado ]
A7: Separar variable [ Nombre:%pasajeros Separador:; Eliminar base:Apagado ]
A8: For [ Variable:%temporal Ítems:%pasajeros(:) ]
A9: Sumar a variable [ Nombre:%cont_pasaj Valor:1 Módulo (wrap around):0 ]
A10: Ir a acción [ Tipo:Etiqueta Acción Número:1 Etiqueta:Ya Te Tengo ] Si (if) [ %temporal ~ %par1 ]
A11: End For
A12: End For
A13: Flash [ Texto:Pasajero no encontrado… Largo:Apagado ]
A14: Detener [ Con error:Apagado Tarea: ]
<Ya Te Tengo>
A15: Destino (de goto)
A16: Establecer variable [ Nombre:%Asiento A:%cont_pasaj Calcular:Apagado Añadir:Apagado ]
A17: Establecer variable [ Nombre:%Vagon AEn castellano más o menos corriente:

A1 - copiar el contenido de la variable global %Tren a la variable local %vagon
A2 - generar la matriz %vagon cuyas hijas %vagon1,%vagon2... son las listas completas de pasajeros de cada vagon>
A3 - poner a 0 el contador de vagones: %cont_vagon
A4 - mediante un bucle FOR buscar exhaustivamente el nombre del pasajero Josefa Antón (%par1) en la lista de nombres de cada vagón
A5 - empieza con %vagon1
A6 - por si ha hecho todo el bucle y no ha encontrado el nombre en un vagón, pone el contador de asientos a 0 antes de empezar con el sigüiente.
A7 - genera la matriz que contiene la lista de pasajeros del vagón
A8 - inicia el bucle para comparar el nombre %par1 con los de las lista
A9 - y incrementa el contador de pasajeros
A10 - si el nombre de la lista coincide con %par1, vete a la etiqueta (goto) Ya Te Tengo
A11 - acaba el bucle dentro del vagón y como no ha encontrado el nombre (si lo hubiera encontrado habria saltado a la etiqueta)...
A12 - vuelve al primer bucle, donde incrementa %cont_vagon y busca en el vagón sigüiente.
A13 - si se acaban los vagones: Flash "Pasajero no encontrado"
A14 - y se acaba la Tarea
A15 - peeeeeero, si lo ha encontrado...
A16 - copia a la variable %Asiento el valor %cont_pasaj
A17 - y en %Vagon el valor de %cont_vagon en el momento que ha encontrado a Josefa Antón.

La tarea es muy básica pero funciona. Deberia completarse para ofrecer solución a dos problemas que, de entrada, se me ocurren: ¿que pasa si hay dos pasajeros con igual nombre y apellido?. ¿Como podria saber el número de asientos libres?... Lo dejo como ejercicio para nota...!

MALDITO TECLADO!

Si tenemos que cargar una matriz con un número de datos importante (en el ejemplo propuesto habria 8x50=400 nombres y apellidos) se nos presenta un problema: vamos a pasarnos un buen rato tecleando datos, repasándolos y rectificando posibles errores con un teclado de la Srta. Pepis...

Al mismo tiempo muchas veces ya tenemos (o podemos tener) estos datos en una tabla de Excel. Esto facilita mucho el trabajo de leer los datos y meterlos en una variable. ¿Cómo? Voy a exponer como lo hago yo.

Suponemos pues que ya tenemos los datos en una hoja de cálculo en Excel. Una tabla con filas y columnas que deberemos preparar así:

1 - Eliminamos encabezamiento de columnas (títulos), colores, etc. dejando la tabla limpia. Si queremos conservar la original podemos hacer una copia con otro nombre. Es aconsejable eliminar también los libros 2 y 3 que, por defecto, nos coloca Excel.
2 - Eliminamos los puntos separadores de miles seleccionando todos los campos de la hoja y, en Formato, desactivar el separador de miles.
3 - Luego, en "Archivo", seleccionamos "Guardar como" con la opción "Archivo separado por comas (csv)"
4 - Una vez guardado el archivo salimos de excel y lo enviamos por correo a nuestra propia dirección para tenerlo en el teléfono.
5 - Ya desde el teléfono abrimos el correo y guardamos el archivo donde lo hacemos normalmente.
6 - Abrimos Tasker y nos creamos una pequeña tarea con una sola acción Leer archivo a la variable que queramos (%Tren en el ejemplo) y, que si vamos justos de memoria RAM puede ser incluso una variable local... (podria ser %tren en el ejemplo), indicando la ruta del archivo.
7 - Excel inserta saltos de línea al final de cada fila de datos. Para eliminarlos (hay otros métodos) yo lo hago así: Variable %Tren Buscar y reemplazar Buscar /n Reemplazar con #
8 - Como Excel separa los datos con ; ya tenemos el separador de datos dentro de cada fila (nombres). El separador de columnas (vagones) será #
9 - IMPORTANTE Como Excel, por defecto, utiliza como separador de decimales la coma "," mediante un nuevo Variable > Buscar y reemplazar , por . tendremos que los datos numéricos con decimales ya serán operables con Tasker.

MATRICES DE TRES DIMENSIONES

No voy a entrar en ello, lo voy a dejar como una reflexión en caliente solamente: Si en lugar de los nombres hubiera escrito en %Tren una variable como la que he creado al principio del artículo %fulano conteniendo Martínez|Pérez|Luis|12-03-1975|Barcelona, podria extraer los datos de cada pasajero mediante una acción Separar Variable utilizando el separador |. Tendria una matriz de tres dimensiones!

A partir de estos datos podria realizar tareas que respondieran a preguntas del tipo: ¿Que dia nació el pasajero que ocupa el asiento x del Vagón Y? ¿Cuantos Pasajeros de llaman Luís? o ¿Cuantos residen en San Sebastián?...

CONCLUSIÓN

En el transcurso de la lectura de este artículo, si habeis sido pacientes y habeis llegado hasta aquí, es muy probable que ya se os haya ocurrido alguna idea para realizar un programa que os sea útil. Muchos de nosotros usamos hojas de cálculo de Excel: listas de precios por modelos y tamaños, tablas de calificaciones (con los alumnos en filas y las distintas asignaturas en columnas de la que se pueden extraer medias, notas máximas, listas de suspensos...), horarios de autobuses según destinos, etc. hay un mundo entero de datos en hojas de cálculo en Internet. Tampoco se trata de crear una base de datos como la de la SS, pero seguro que se os ocurren aplicaciones.

A mí se me está metiendo en la cabeza la idea (mucho más abstracta) de hacer una tarea multipropósito para gestionar la consulta de datos de variables preparadas para convertirse en matrices de dos dimensiones. Tal vez sea mi próximo proyecto.

Bueno, lo dejo para más adelante, ahora sólo se me ocurre añadir una cosa: Pasajeros, al tren!

AÑADIDO: Referencia donde Caravantes proporciona un método para evitar caracteres "raros" en los archivos extraidos de Excel:

Interesantísimo, como siempre, muchas gracias.

Respecto al bug de los caracteres especiales... Supongo que sabes que el juego de caracteres ASCII básico (128 caracteres) nunca da problemas... pero eso no incluye ningún carácter acentuado ni eñes, etc. Para añadir esos otros caracteres especiales se inventaron otros sistemas de codificación más complejos, el problema es que no hay unanimidad en su uso. Por defecto, Windows codifica con el sistema ISO 8859-1 (europeo occidental), pero Android usa otro sistema. ¿Cuál?

Yo lo descubrí haciendo la operación inversa. Utilizando Tasker, generé un archivo TXT que contuviera caracteres especiales. Luego llevé ese archivo a Windows y lo abrí con Word. En ese momento, Word abrió una ventana para que yo indicase cuál era la codificación adecuada; podía ir probando con los diferentes sistemas de codificación y viendo una "vista rápida" del resultado. De esa forma comprobé que la codificación correcta era UNICODE UTF-8.

Ahora viene la segunda parte: Cómo generar (en Windows) un archivo con esa codificación, para que funcione bien en Android. Abres el fichero con el Word. Eliges ARCHIVO > GUARDAR-CÓMO. Seleccionas el tipo TEXTO SIN FORMATO, y le das a GUARDAR. Aparecerá otra ventana en la que podrás especificar el sistema de codificación; eliges OTRA-CODIFICACIÓN y luego UNICODE UTF-8. El fichero así generado funcionará perfectamente en Android, incluyendo sus caracteres especiales.

Más detalles e información en las páginas siguientes

Codificación de caracteres
http://es.wikipedia.org/wiki/Codific..._de_caracteres (http://es.wikipedia.org/wiki/Codificaci%C3%B3n_de_caracteres)

Elegir la codificación de texto al abrir y guardar archivos
http://office.microsoft.com/es-es/su...010121249.aspx (http://office.microsoft.com/es-es/support/elegir-la-codificacion-de-texto-al-abrir-y-guardar-archivos-HA010121249.aspx)

mlesir
19/04/14, 19:32:47
El tutorial es impresionante. Solo puedo darte la enhorabuena y las gracias.
Quizá te interese esto que escribí hace un tiempo es un proyecto para crear matrices de tres dimensiones sin usar el separar variable.

http://www.htcmania.com/showthread.php?p=8304313

Nunca lo llegue a concretar. Me gustaría que lo vieras para ver si crees que tiene posibilidades.

Básicamente consiste en guardar los datos asi: (solo utiliza dos variables para todo, en el ejemplo %Var para guardar e %Indice para guardar/buscar)

Fórmula buscar guardar: %Índice X *10

%Var10..%Var11..%Var12......%Var19
(jose) (martinez) (telefono) (direccion)

%Var20...%Indice:x*10+x

%Var30
.....
%Var90

Ahora la tercera dimension:

%Indice:x*100

%Var100.....amigos

%Var110/jose)..... %Var111/Martínez.. Etc


%Var120/paco.....

No se si con este esquema queda más o menos claro pero pero es solo para que os hagáis una idea. En el enlace queda más claro.
Por otro lado creo que la nueva posibilidad en la versión de Tasker 4.3 de nombrar con una variable a otra (%%Var) nos abre creo las puertas a crear verdaderas matrices sin recurrir a separar varíables.
Pero el método que usemos depende claro de que queremos primar rapidez o espacio en memoria.

cace0353
19/04/14, 20:13:16
Hola Mlesir, ya me leí tu trabajo-propuesta en mi navegación por este foro documentandome y me pareció muy "currada" (enseguida me recordó el primitivo Basic con números de línea que poníamos de 10 en 10 y que, según he leido en otros posts tuyos, también trasteaste).

Es una idea muy interesante y expresa un gran dosis de imaginación (¿te cuesta, como a mí, dormirte por las noches?). Pero también creo que a base de simplificar el uso de recursos se convierte en muy abstracta, difícil de pillar para los demás...

Podría ser una "bomba" si encontráramos la manera de convertirla en una Acción del propio Tasker (o un pluguin) de manera que el usuario-programador la manejara desde fuera pasándole unos parámetros del tipo: devuélveme lo que tengo en la fila F columna C ó fórmulas del estilo de las que se utilizan en Excel: Buscarv, Media, etc.

De momento aún estoy muy verde para programar plugins (ni idea de Linux).

Por eso he apuntado al final del artículo una tarea (también muy abstracta) multipropósito para operar con matrices. Desde luego no está muy alejada de tu linea. Sólo nos falta desarrollarlas...

Caravantes
19/04/14, 22:31:23
Uso de variables y matrices en Tasker

Excelente aporte, muy currado. Cace, muchas gracias.

Me ha gustado especialmente esa idea de utilizar subtareas para extraer datos de una matriz, desembarazando de esa labor a la tarea principal. Ya puestos, me plantearía hacer una subtarea más genérica que sirviera para cualquier matriz, y en tal caso habría que indicar a la subtarea A) el número de dimensiones, B) los caracteres separadores de cada dimensión y C) las coordenadas del dato a obtener; esos tres datos se podrían pasar concatenados en el parámetro 1, al estilo siguiente:
2-#;-3-2 (lo cual podría significar algo así:
-matriz de 2 dimensiones
-Separadores: # (separador de mayor nivel, vagón) y ; (separador de menor nivel, asiento)
-Dato buscado (nombre del pasajero) en el la posición 3-2 (vagón 3, asiento 2).
En el parámetro 2 se podría pasar una variable local con el contenido de toda la matriz, y de esta forma la subtarea funcionaría igual sobre matrices Globales o locales.

cace0353
19/04/14, 23:35:26
Hola de nuevo, Caravantes,

Precisamente esto lo que me bulle ahora en la cabeza...

La idea que he intentado expresar y (si puedo) convertir en tarea es, a grandes rasgos, lo que propones:

Una tarea que pueda ser llamada desde cualquier otra para manejar cualquiera de nuestras bases de datos guardadas como un archivo de texto y "preparadas" para convertirlas en una matriz de dos dimensiones como en el ejemplo del artículo. Lo de las dimensiones es fijo: 2 (al menos en principio) si solo tenemos datos en una linea sirve igualmente.

La idea consistiria en pasar como parámetros a la subtarea, que puedo llamar BDatos, lo sigüiente:
%par1 = (concatenando los datos con un separador) el nombre y ruta del archivo de texto de donde sacar los datos + un nemotècnico o palabra-clave de que hacer con los datos.
Por ejemplo y continuando con el del artículo, siendo el archivo importado de Excel: Tren.txt y lo que quiero hacer sea "Guardar un dato en la celda B6" (columna B, fila 6)

Establecer variable %par1 A /Tasker/Tren.txt;GD_en_CF

Y en %par2 el numero de parámetros que necesite para procesar cada uso distinto. En este caso sólo 2: columna y fila

Establecer variable %par2 A B;6

Ejecutar tarea BDatos %par1 %par2

Y en la tarea BDatos tendria

Una parte común:

- Separar Variable %par1 separador ;
- Leer archivo %par11 A %datos (esta seria la variable, preparada al guardar el archivo para ser convertida en matriz, y fuente de datos de la Subtarea. En el ejemplo leeria el archivo Tren.txt a la variable local %datos)
- Establecer variable %orden a %par12 (esta seria la 2ª hija de %par1, es decir el nemotécnico de que hacer con los datos)
- Separar variable %par2 separador ; (de aquí saldrian los parámetros necesarios y que habria encadenado en la tarea principal. En el caso del ejemplo sólo 2: %par21=B y %par22=6

y luego filtraria la ejecución según sea %orden con los parámetros específicos que indicara %par2 (en este caso B y 6) Por ejemplo:

IF %orden coincide con GD_en_FC (guardar dato en fila y columna)
.......
.......
End IF

No sé si me he explicado bién, pero habria un IF - End IF para casa cosa concreta que quisiera que hiciera la subtarea.

De momento y a bote pronto se me ocurren: Guardar dato en fila-columna, Borrar el dato que hay en fila-columna, Buscar dato/s que coincide/n con X, Indicar operaciones matemáticas a realizar con los datos de fila-columna, ver que valor en la columna A le corresponde al valor n en la columna M, etc... y ya paro.

La utilidad seria enorme, no os parece?

cace0353
20/04/14, 12:02:18
Hola de nuevo,

La idea sigue madurando y tomando consistencia.

De momento estoy estableciendo como va a funcionar esta macrotarea que he llamado BDatos, que le voy a pedir, como se lo voy a pedir, y que me va a proporcionar. El ¿Como va a trabajar? ya ha quedado apuntado en el post anterior.

Como los archivos exportados en .CSV Excel los puede abrir como verdaderas hojas de cálculo de un sólo libro, voy a mantener los nombres de archivo con la extensión .CSV y Tasker los leerá igualmente a la variable local de datos, quitará los saltos de línea substituyéndolos por # etc, etc... Ventaja importante: así puedo hacer un mantenimiento de mis bases de datos desde el PC.

También voy a incluir en la macrotarea BDatos una serie de acciones de manera que, al modificar o añadir registros en cada base de datos, se actualize el archivo de orígen .CSV, tal como hacia en la primera versión de mi primer proyecto de ayudas a la navegación, borrando todo el archivo y guardando de nuevo por líneas en el archivo .CSV las hijas de %datos con Escribir Archivo.

Esto creo que es fácil de conseguir y tiene unas prestaciones mayúsculas: Si guardo todos los archivos de datos .CSV de Tasker en mi carpeta de Dropbox (o en Google Drive...) del teléfono, siempre tendré mis bases de datos actualizadas en la nube y accesibles con Excel desde cualquier PC.

En esta fase de gestación y planificación del trabajo voy a seguir posteando estas ideas porqué:
- Me sirven de guión escrito para el desarrollo posterior del código de la tarea.
- Abro las puertas a sugerencias por parte de la gente que siga este post para, si puedo, incorporarlas a mi proyecto o rectificar mis planteamientos..

De momento es todo, pero el "tarro" no para!

Buenos dias y saludos a todos!

Caravantes
20/04/14, 13:41:41
Abro las puertas a sugerencias por parte de la gente que siga este post para, si puedo, incorporarlas a mi proyecto o rectificar mis planteamientos..

En un proyecto así yo siempre tendría claro que uno de los datos (parámetros) que hay que entregar a la (sub)tarea sería la identificación del archivo: unidad-ruta-nombre-extensión. Eso puede ir todo junto, no hay ningún buen motivo para separarlo. Por tanto, no veo relevante que estés eligiendo un tipo de extensión (.CSV), pues todas las extensiones deben ser igual de operativas en la tarea Tasker. Es claro que la extensión .CSV tiene esas ventajas concretas que has citado, igual que la ubicación en la carpeta de Dropbox tiene ventajas concretas que también has mencionado. Pero creo que la tarea Tasker debe ser independiente de esos plantemientos, debe funcionar igual con archivos que estén en otra ubicación y/o tengan otra extensión (o carezcan de extensión).

Una posibilidad interesante es que la tarea principal nunca se comunique directamente con el archivo, que en ese proceso siempre intervenga como intermediaria la sub-macrotarea BDatos. En este sentido, yo creo que algunas de las funciones de la tarea BDatos podrían ser:
- Devolver a la tarea principal todo el contenido del archivo. El dato devuelto sería una matriz local, o un "Fail" si no se pudo acceder al archivo o el archivo estaba vacío.
- Devolver a la tarea principal el número de filas y columnas del archivo. El dato devuelto sería una pareja de números (al estilo "320;12") o bien un Fail.
- Guardar en un archivo una tabla vacía con el número de filas y columnas que se indiquen: el archivo solo contendrá los separadores, sin datos. El dato devuelto sería un Ok o un Fail (si no se pudo guardar el archivo).
- Devolver a la tarea principal un subgrupo de datos (una fila o una columna determinada). El dato devuelto sería una matriz local, o un Fail (archivo no accesible; o dato imposible si se ha pedido una fila/columna que no está en el archivo).
- Devolver a la tarea principal un dato concreto (fila y columna especificadas). El dato devuelto es el contenido de una variable simple, o un Fail.
- Guardar en el archivo toda la matriz que haya establecido la tarea principal. El dato devuelto sería un Ok o un Fail si no se pudo grabar en el archivo.
- Guardar en el archivo un subgrupo de datos (una fila o una columna determinada). El resto de datos serán los que ya hubiese en el archivo. El dato devuelto sería un Ok o un Fail (archivo no accesible; o número de elementos no coincidentes con la tabla del archivo).
- Guardar en el archivo un dato concreto (fila y columna específicadas). El dato devuelto sería un Ok o un Fail.
- Obtener el número de veces que aparece un dato en el archivo. El dato devuelto es un número natural, o un Fail.
- Obtener las posiciones (parejas de fila-columna) ocupadas por un dato concreto. El dato devuelto es una pequeña matriz conteniendo parejas de coordenadas (al estilo "3;2#3;6#320;124") o bien un "0" o bien un Fail.

Implementar todas estas opciones seguramente genere una tarea demasiado mastodónica, poco práctica. Una posibilidad es dividir las funciones en dos tareas, por ejemplo una tarea para todas las operaciones de lectura y otra para todas las operaciones de escritura. Independientemente, quizá convenga priorizar cuáles funciones son las más necesarias, descartando el resto.

Creo que esto empieza a parecerse mucho a SQLite. Quizá incluso se podría usar SQLite para hacer algunas de estas funciones... o a la inversa: quizá podría utilizarse esta macrotarea para acceder a bases de datos convencionales, como la de Whatasapp.

cace0353
20/04/14, 23:36:01
Implementar todas estas opciones seguramente genere una tarea demasiado mastodónica, poco práctica. Una posibilidad es dividir las funciones en dos tareas, por ejemplo una tarea para todas las operaciones de lectura y otra para todas las operaciones de escritura. Independientemente, quizá convenga priorizar cuáles funciones son las más necesarias, descartando el resto.

No creas Caravantes, el código se ejecuta línea a línea (lenguaje interpretado) por lo tanto los 10 o 12 filtros IF.....End If que pueda haber (todos menos el que cumpla) se saltan en la primera línea (el IF) y la ejecución del programa salta hasta después del End IF. Si no le pedimos a la tarea algo qoe no está previsto se la fuma en un momento, sólo ejecuta el grupo de acciones del IF que se cumple.

Pienso, pues, que aunque la tarea pueda llegar a ser muy pesada en cuanto a cantidad de texto (código) escrito también quedará más modulada: cada filtro IF-EndIF será como una sub-tarea por si mismo. En resumen: mucho código pero pocas nueces.

Por cierto, y viendo tus sugerencias relativas a lo que le podemos pedir a la tarea: ¿que interés puede tener crear un arxivo de base de datos vacio? ¿en que uso concreto piensas?

En un post (asociar dirección a los Contactos de Google en el proyecto de ayudas a la navegación en coche) Mlsir ya me sugeria lo de las bases de datos en Sqlite3. Me lo miré por Internet para informarme un poco y, la verdad, se sale de mis aspiraciones. Me gusta y me divierte :idea: programar y resolver retos con las herramientas que tengo a mano, pero meterme a aprender el manejo de bases de datos Squlite.... se va de mis pretensiones, de momento.

Un compañero al comentarle en lo que estaba metido ahora (él también conoce Tasker) me dijo, no hace mucho: y porqué no lo programas en lenguaje Web (HTML), es multiplataforma y no es difícil. Le respondí exactamente lo mismo que he dicho antes.

Saludos cordiales y gracias por vuestro estímulo.

Caravantes
21/04/14, 01:33:29
No creas Caravantes, el código se ejecuta línea a línea

No lo digo por eso, la máquina no tiene problemas con ello, soy yo quien se abruma con tareas de 100 acciones o más: me resulta tedioso usar el scroll todo el rato, y con tanto movimiento vertical es fácil equivocarse: sin querer cambio de sitio una acción o incluso la llevo a la papelera sin darme cuenta, ya me ha pasado. Con estas tareas tan pesadas sería una ayuda importante poder utilizar el ordenador para construirlas y modificarlas, de ésto también hemos hablado y yo sigo sin encontrar por ahora una buena solución.

El interés de crear un fichero con una tabla vacía... en algunas tareas puede ser interesante ir rellenando las casillas de la tabla según vayan surgiendo los datos (o según se vayan obteniendo, por la vía que sea). Pero creo que aparecerán más dificultades si tratas de crear la tabla al mismo tiempo que guardas el primer dato. Por un lado habría que pasarle más parámetros a la subtarea: A) el dato, B) las coordenadas de ese dato y C) también las dimensiones de la tabla. Además, yo había pensado que la "rutina" de guardar un dato debe comprobar que la tabla existe previamente (y devolver un Fail si el archivo no existe). Creo que todo eso se simplifica si tienes una rutina para crear la tabla vacía en el archivo (da igual si el archivo existe previamente, o si no existe, porque lo crea/sobreescribe), y otra rutina para guardar datos en una tabla que siempre debe existir previamente. En todo caso, son dos "rutinas" dentro de una misma tarea, así que desde una de ellas puede llamarse a la otra si fuera necesario encadenar ambas acciones.

Igualmente puede concebirse de otra forma, no estoy nada seguro de que mis propuestas sean realmente buenas, son propuestas tipo brainstorm que no pretenden sentar objetivos sino ayudar a pensar en posibilidades que luego conviene matizar y depurar.

En este mismo sentido, se me acaba de ocurrir otra idea brainstorm: que se le pueda pedir a la macro-tarea que cambie el tamaño (número de filas y/o columnas) de una tabla ya existente en un fichero.

cace0353
21/04/14, 09:52:44
Hola Caravantes, gracias por tus sugerencias y buenos dias

De hecho mi proyecto pretende ser una tarea tal-cual, en principio no cuento con que el usuario final la modifique. El propósito era el de ofrecer una tarea que se podría integrar como una acción más de Tasker (por esto sugeria la posibilidad de convertirla en un plug-in).
Así pues el usuario-programador de Tasker la podria usar "sin" modificarla, indicándole con los parámetros el que necesitaba de la tarea. Algo así como las fórmulas de Excel: hay un montón de funciones que se usan respetando su sintaxis (¿te has fijado que los : i ; de los parámetros que se ponen en las fórmulas de Excel se asemejan mucho a la manera de escribir las matrices de Tasker?).

Pues bién, en principio el usuario corriente no deberia entrar a modificar la tarea a menos que quisiera ampliar su contenido o editar la manera de trabajar.

Por lo que respecta a lo de la alteración involuntaria o accidental de líneas de código creo que he visto por ahí que se pueden bloquear. A lo mejor sólo se pueden bloquear partes de las escenas (no estoy seguro..) pero de momento y mientras no sea un problema gordo no está entre mis objetivos immediatos averiguarlo...

Para lo de la visibilidad de los filtros, tú mismo publicaste aquí http://www.htcmania.com/showthread.php?t=814267 varios trucos con las etiquetas grandes y la ocultación de bloques enteros de código :-) Y la verdad es que són muy útiles! No me haria falta ni crear condiciones falsas: justamente los filtros para cada opción son IF.

Para lo otro que sugieres: está resuelto "de oficio"
En los lenguajes "antiguos" de programación (para hombres...je,je) las variables, antes de usarlas, habian de ser declaradas indicando el tipo de datos que contendrian. Las matrices habia que decir que contendrian del mismo modo y dimensionarlas con filas y columnas.

En Tasker no es necesario. Con Array push añades filas y columnas Hasta el infinito y más allá!.

En el ejemplo del tren:

¿Quiero añadir un vagón?: Añado una lista de pasajeros separados por ; y empezando con # y luego Array push %vagon9 (seria una nueva columna si tengo los números de asientos en las filas)

¿Quiero añadir 1 asiento?: Añado con un bucle FOR un %pasajero51 en cada %vagon con Array push! (seria una nueva fila de la tabla...)

Finalmente, lo del archivo: habia pensado que al final de la tarea BDatos pondria uns acciones para actualizar el fichero de datos, borrándolo todo y escribiéndolo de nuevo con los datos modificados.
Como la escritura se hace con Escribir archivo y lo que se escribe es la variable %tren sólo debo incluir en la tarea los Array push de lineas o columnas para tener %tren actualizada. (en el ejemplo práctico solo columnas por si añado un vagón, pero en la tarea multipropósito debo mantener las dos posibilidades)
Y si el archivo no existe, la acción Escribir archivo dándole un nombre.extension y con Añadir marcado, lo crea automáticamente en la raíz de la tarjeta.

Como lo ves?

EDITO Acabo de darme cuenta de que es más complicado añadir filas que columnas. Es una limitación por la estructura de arbol de las matrices en Tasker. Al añadir una rama (%vagon) al tronco añado de una vez un monton de "ramitas" (%pasajeros) como columna. Al añadir filas debo añadir una "ramita" (%pasajero) a cada rama (%vagon) con un bucle FOR. Tendré que trabajar más este tema ya que no resulta indiferente elegir para un rango de datos determinado ponerlo en filas o en columnas...

Rbcheca
22/08/15, 06:21:36
Gracias, gracias, gracias, esto me viene que ni pintado.