sábado, 14 de febrero de 2009

Ejercicio 15. Listas.


Concepto de lista

Una lista es una estructura de datos que nos permite almacenar varios elementos de información como un único objeto.

El concepto de lista en Netlogo es equivalente al concepto de vector o array en otros lenguajes de programación.

En Netlogo, las listas se representan con dos corchetes entre los cuales se introducen los elementos que componen dicha lista. Ejemplos de lista son [3 6 83 4 2] [“a” “f” “h” “o”] [3 1 “hola” 4 1]. Un factor a tener en cuenta es que Netlogo comienza a numerar las listas a partir del elemento 0. Es decir, que, por ejemplo, para la lista [12 4 5], 12 sería el elemento 0; 4 el elemento 1 y 5 el elemento 2.

¿Cómo construir una lista?

Depende de si los datos que componen la lista son conocidos a priori o no.

  • Si los datos son conocidos:

    Para crear una lista, simplemente escribiremos entre corchetes los datos individuales que queremos que formen parte de la lista. Por ejemplo, para crear un lista llamada “a” con los elementos 1 2 3 4 5 6 7 simplemente escribiremos:
    let a [ 1 2 3 4 5 6 7]

  • Si los datos que forman la lista no son conocidos:

    Si los datos que van a formar parte de la lista no son conocidos a priori, sino que son variables del programa (caso más habitual), deberemos emplear la primitiva list: list recibirá una serie de argumentos y nos devolverá una lista con los estos argumentos en el mismo orden en que se los hemos pasado.

    La sintaxis de list depende del número de argumentos que recibe:

    - Si recibe 2 argumentos, simplemente escribiremos los argumentos entre corchetes:
    list [a b] ;; nota: a y b son números o variables

    -Si recibe 3 o más argumentos, escribiremos list seguido de los argumentos que compondrán la lista, sin corchetes y con paréntesis englobando toda la sentencia (inluida la primitiva list):
    (list a b c d e f g h i j k) ;; nota: a, b, c, d, e, f, g, h, i, j, k son números o variables

¿Cómo acceder a los elementos de una lista?

Para acceder al primer elemento de una lista usamos la primitiva first. Ejemplo:
first [a b c d e f g h i j k] --> a ;; nota: a, b, …, k son números o variables.

Para obtener el último elemento de la lista utilizamos el primitiva last:
last [a b c d e f g h i j k] --> k ;; nota: a, b, …, k son números o variables.

Para obtener todos los elementos de la lista excepto el primero se emplea la primitiva but-first. Ejemplo:
but-first [a b c d e f g h i j k] --> [b c d e f g h i j k] ;; nota: a, b, …, k son números o variables.

Para obtener todos los elementos de la lista excepto el último se emplea la primitiva but-last:
but-last [a b c d e f g h i j k] --> [a b c d e f g h i j] ;; nota: a, b, …, k son números o variables.

Para obtener el elemento n de la lista, empleamos la primitiva item. Ejemplo:
item 5 [a b c d e f g h i j k] --> f ;; nota: a, b, …, k son números o variables.
Nota: Recuerda que Netlogo numera las listas a partir del elemento 0.

Para tomar un elemento al azar de una lista se emplea la primitiva one-of:
one-of [a b c d e f g h i j k ] --> cualquier elemento de la lista tomado al azar

Y para tomar varios elementos al azar de una lista empleamos n-of:
n-of 3 [a b c d e f g h i j k ] --> nos devuelve otra lista con 3 elementos de la lista inicial tomados al azar.

¿Cómo modificar una lista?

Para introducir un nuevo elemento al comienzo de una lista, empleamos la primitiva fput:
fput z [a b c d e f g h i j k ] --> [z a b c d e f g h i j k ] ;; nota: a, b, …, k son números o variables.

Y para introducirlo al final de la lista, utilizamos la primitiva lput:
lput z [a b c d e f g h i j k ] --> [a b c d e f g h i j k z] ;; nota: a, b, …, k son números o variables.

Para eliminar un elemento de una lista, usamos la primitiva remove:
remove d [a b c d e f g h i j k ] --> [a b c e f g h i j k ] ;; nota: a, b, …, k son números o variables.
Nota: remove elimina todas las paraciciones del elemento en la lista.

Si conocemos la posición que ocupa un elemento dentro de una lista, podemos eliminarlo con la primitiva remove-item:
remove-item 4 [a b c d e f g h i j k ] --> [a b c d f g h i j k] ;; nota: a, b, …, k son números o variables.
Nota: Recuerda que Netlogo numera las listas a partir del elemento 0.

Una variación de la primitiva remove es la primitiva remove-duplicates, que elimina todos los elementos repetidos en la lista, dejando únicamente la primera aparición de los mismos. Ejemplo:
remove-duplicates [a a b b b c c d e e e e e f f g g h h i i j j j k k ] --> [a b c d e f g h i j k]

Para reemplazar un elemento de la lista por otro, empleamos la primitiva replace-item:
replace-item 4 [a b c d e f g h i j k ] z --> [a b c d z f g h i j k] ;; nota: a, b, …, k son números o variables.

Otras primitivas últiles relacionadas con listas:

Para conocer la longitud de una lista (esto es, su número de elementos) empleamos la primitiva length:
length [a b c d e f g h i j k ] --> 11 ;; nota: a, b, …, k son números o variables.

Para obtener el elemento que más se repite dentro de una lista (es decir, la moda), se emplea la primitiva modes:
modes [a a b c d e f g h i j k] --> a ;; nota: a, b, …, k son números o variables.

Para conocer la posición de un elemento dentro de una lista se utiliza la primitiva position:
position a [a b c d e f g h i j k ] --> 0 ;; nota: a, b, …, k son números o variables.

Para desordenar aleatoriamente los elementos de una lista utilizamos la primitiva shuffle:
shuffle [a b c d e f g h i j k ] --> [d k a c e i j h f b g] ;; nota: a, b, …, k son números o variables.

Para obtener una lista ordenada de manera inversa a la original, empleamos la primitiva reverse:
reverse [a b c d e f g h i j k ] --> [k j i h g f e d c b a] ;; nota: a, b, …, k son números o variables.

Para obtener una lista con los elementos ordenados en orden creciente, empleamos la primitiva sort:
sort [4 6 2 8 4] --> [2 4 4 6 8]

Nota 1: Recuerda siempre que, para Netlogo, el primer elemento de una lista es el elemento 0.

Nota 2: Recuerda que si los elementos de una lista son caracteres, éstos deben escribirse entre comillas: [“a” “b” “c” “d” “e” “f” “g” “h” “i” “j” “k”]

3 comentarios:

Unknown dijo...

Algunas cuestiones útiles relacionados con las listas:

-Técnicamente, las listas no pueden ser modificadas pero se pueden construir nuevas listas a partir de listas antiguas... incluso con el mismo nombre. Para ello se utiliza la orden set.

-Para concatenar listas se pueden utilizar varias funciones (fput/lput/sentence)
sentence : crea una lista a partir de DIVERSOS valores proporcionados. Si son listas las unifica en la lista final, a no ser que se expresen con doble corchete...
show (sentence [1 2] [3 4] (list [who] of turtles) )
=> [1 2 3 4 [1 3 0 4 2]]
show (sentence [[1 2]] [[3 4]] (list [who] of turtles) )
=> [[1 2] [3 4] [3 0 2 1 4]]


-Para incorporar una nueva lista a una previa lista-de-listas:
set mylist ( list [1 2] [3 4] [5 6] )
set mylist lput [0 0] mylist

-Para modificar listas se utilizan funciones de “extracción de items” en la construcción de listas nuevas.
Ejemplos con set mylist ( list [1 2] [3 4] [5 6] ):
print item 2 mylist =======================> [5 6]
set mylist remove-item 1 mylist ===========> [[1 2] [5 6]]
set mylist replace-item 0 mylist [7 8] ====> [[7 8] [3 4] [5 6]]
set mylist but-last mylist ================> [[1 2] [3 4]]
set mylist but-first mylist ===============> [[3 4] [5 6]]


-Para modificar elementos de listas de listas se pueden anidar las funciones de extracción.
set mylist ( list [1 2] [3 4] [5 6] ) , entonces para cambiar de 6 por un 7.
set mylist (replace-item 2 mylist (replace-item 1 (item 2 mylist) 7 ) )
=> [[1 2] [3 4] [5 7]]


-Para realizar operaciones con cada elemento de una lista, se puede utilizar un bucle lógico con repeat, con while o un procedimiento recursivo. Existen 2 primitivas especiales:

foreach : Realiza un conjunto de operaciones sobre cada elemento de una lista. Se utiliza ? para hacer referencia al valor actual en el bloque de operaciones. Si se mencionan varias listas (deben ser de idéntica longitud) hay que colocar la operación entre paréntesis, se utilizaran valores actuales de cada una de las listas y se utilizará ?1,?2,?n para el valor de referencia de cada lista usada.
foreach mylist [ show (word "Lista: " ? ".") ]
(foreach ( list (turtle 1) (turtle 2) [3 4] ) [ ask ?1 [ fd ?2 ] ] )


map : Función que proporciona una lista que contiene el resultado de aplicar una función a cada uno de los elementos de la original. Con ? se hace referencia al valor actual.
show map [round ?] [1.2 2.2 2.7] =====> [1 2 3]
show map [? < 0] [1 -1 3 4 -2] =======> [false true false false true]


-Para ordenar los elementos de una lista: set mylist sort-by [?1 < ?2] mylist

/!\ Un agentset es un conjunto desordenado de agentes, que cuando son llamados responden cada vez en orden aleatorio. Si se precisa que un conjunto de agentes responda siempre según una secuencia ordenada entonces hay que hacer una lista de agentes. Para ello se utiliza sort y sort-by (con reverse para hacer orden descendente). Por ejemplo, para conseguir listas de:
-Tortugas ordenadas ascendentemente por su identificativo (who): sort turtles.
-Parcelas ordenadas de izquierda a derecha y de arriba a abajo: sort patches.
-Tortugas ordenadas según tamaño: sort-by [[size] of ?1 < [size] of ?2] turtles

-Para ordenar operaciones secuenciales (no concurrentes) a una lista ordenada de agentes:
foreach sort turtles [ ask ? [ {operation block} ] ]

Y, para acabar, una nota sobre el rendimiento de las operaciones con listas: Las operaciones más eficientes y más rápidas son las realizadas con los primeros elementos de las listas (first, butfirst, fput, length), de modo que es preferible siempre añadir elementos con fput. Las más lentas (con listas muuuy largas, claro...) son item, lput, butlast, last, y one-of.

Espero que sea de tanta utilidad como el fabuloso curso de David.
Un saludo,
Miguel (SSASA-UAB)

hiram_economia dijo...

OYE GRACIAS POR CONTESTAR A MIS INQUIETUDES
AHORA, ME PARECE QUE ESTO ES MUY BUENO PARA TODOS AQUELLOS QUE SE INICIAN EN EL NETLOGO, PERO, NECESITAMOS MAS, QUE PAGINA ADEMAS DE LA TUYA 8QUE ES BUENISIMA ) NOS RECOMIENTAS, O SEGUIRAS CON EL MANUAL DESPUES...?

DP dijo...

Gracias por tus palabras, hiram_economia.

Para seguir adelante, te recomiendo que en primer lugar le eches un vistazo a la guía de inicio rápido a Netlogo de Luis Izquierdo (tienes en enlace en la parte derecha del blog). Es un documento muy útil para iniciarse en Netlogo, pues en ella está recogida toda la información necesaria para comenzar con Netlogo en un documento breve y práctico, ideal para guardarlo como referencia y refrescar conocimientos de Netlogo cuando hemos estado separados un tiempo de este lenguaje de programación.


A continuación, para seguir practicando, yo le echaría un ojo a la biblioteca de modelos de Netlogo (en la barra de herramientas de Netlogo, entra en file y a continuación en models library. Allí encontrarás muchos ejemplos de modelado basado en agentes. Te recomiendo que comiences por la carpeta code examples. Los modelos que aparecen aquí son muy sencillos -en cuanto a programación se refiere- y te servirá para familiarizarte con otras funcionalidades de Netlogo.


En breve actualizaré el blog con nuevas entradas, por lo que te recomiendo que te pases por aquí de vez en cuando.

Un saludo,
DP.