4.4 Detalles de las colecciones

Las categorías de clases Collections- son las más prolíficas, hay 7 de ellas conteniendo 46 clases.

La categoría Collections-Abstract agrupa clases que se consideran abstractas. Una clase abstracta no se puede instanciar, su comportamiento se declara pero no se implementa por completo. Es responsabilidad de sus subclases implementar la parte del comportamiento que falta.

Una clase abstracta es útil para establecer un conjunto de métodos polimórficos que se espera que cada una de sus subclases concretas especialice. Esto captura y comunica nuestra intención.

Observe cómo se declara el importante método #do:, pero no se implementa:

Collection>>do: aBlock 
"Evaluate aBlock with each of the receiver's elements as the argument."
self subclassResponsibility

A continuación, observa cómo lo implementan dos subclases diferentes de Collection:

OrderedCollection>>do: aBlock 
firstIndex to: lastIndex do: [ :index |
   aBlock value: (array at: index) ]

and:

Dictionary>>do: aBlock
super do: [:assoc | aBlock value: assoc value]

Hay que distinguir dos grupos importantes de colecciones: las colecciones con un tamaño fijo y las colecciones con un tamaño variable.

Colección de tamaño fijo. Estas colecciones se agrupan en la categoría Collections-Arrayed. La más destacada es Array, cuyo tamaño (el número de elementos que puede contener) se establece al crear la instancia. Una vez instanciada, no se pueden añadir ni eliminar elementos de una matriz.

Hay diferentes formas de crear una instancia de Array:

array1 := #(2 'Apple' $@ 4) "create at compile time"
array1b := {2 . 'Apple' . 2@1 . 1/3 } "created a execution time"
array2 := Array with: 2 with: 'Apple' with: 2@3 with: 1/3.
array3 := Array ofSize: 4 "an empty array with a 4 element capacity"

Ejemplo 4.9: Colección con un tamaño fijo

El array array1 y el array1b son un poco diferentes. El primero se crea y se rellena con su contenido durante la compilación del código, por lo que sólo se puede rellenar con elementos literales como enteros, flotantes o cadenas. El segundo se crea en el momento de la ejecución del código y se puede rellenar con elementos instanciados en ese momento, como instancias de Fraction o Point.

Puedes acceder a elementos con una gran variedad de mensajes:

array1 first ⇒ 2
array1 second ⇒ 'Apple'
array1 third ⇒ $@
array1 fourth ⇒ 4
array1 last ⇒ 4
array1 at: 2 ⇒ 'Apple'
array2 at: 3 ⇒ 2@3
array2 swap: 2 with: 4 ⇒ #(2 1/3 2@3 'Apple') 
array1 at: 2 put: 'Orange'; yourself ⇒ #(2 'Orange' $@ 4)
array1 indexOf: 'Orange' ⇒ 2

Ejemplo 4.10: Acceso a elementos de colección

Utiliza el System Browser para descubrir formas alternativas de acceder a los elementos de una colección.

 CuisLogo ¿Cuál es el mensaje adecuado para acceder a los dos primeros elementos de la colección array1?

Ejercicio 4.12: Acceder a parte de una colección

Sin embargo, no se puede añadir ni eliminar ningún elemento:

array1 add: 'Orange'
⇒ Error: 'This message is not appropriate for this object'
array1 remove: 'Apple'
⇒  Error: 'This message is not appropriate for this object'

Sin embargo, es posible rellenar una matriz de una sola vez:

 CuisLogo ¿Rellenar todos los elementos de array1 con ’kiwi’ de una sola vez?

Ejercicio 4.13: Rellenar un array

Colección de tamaño variable. Dichas colecciones se agrupan en varias categorías de clases: Collections-Unordered, Collections-Sequenceable, etc. Representan las colecciones más comunes.

Es destacable OrderedCollection. Sus elementos están ordenados: los elementos se añaden uno tras otros en secuencia19. Su tamaño varía dependiendo de los elementos añadidos o eliminados.

coll1 := {2 . 'Apple' . 2@1 . 1/3 } asOrderedCollection
coll2 := OrderedCollection with: 2 with: 'Apple' with: 2@1 with: 1/3
coll3 := OrderedCollection ofSize: 4

Ejemplo 4.11: Colección con un tamaño variable

El acceso a los elementos es idéntico al de una instancia de Array, pero las colecciones dinámicas te permiten añadir y eliminar elementos:

coll1 add: 'Orange'; yourself
⇒ an OrderedCollection(2 'Apple' 2@1 1/3 'Orange')
coll1 remove: 2@1; yourself
⇒ an OrderedCollection(2 'Apple' 1/3)

Ejemplo 4.12: Añadir, eliminar elementos de un array dinámico

 CuisLogo ¿Cómo añadir ’Orange’ después de ’Apple’ en coll1?

Ejercicio 4.14: Añadir un elemento después

Set. Set es una colección desordenada sin elemenntos duplicados. En cambio, el orden de los elementos no está garantizado. Observa cómo pi es el primer elemento del set:

set := Set new.
set add: 1; add: Float pi; yourself
⇒ a Set(3.141592653589793 1)

Ejemplo 4.13: Colección Set

Se garantiza que no habrá duplicados, incluso con varios tipos diferentes. Fíjate cómo 1, 3/3 y 1.0 se consideran iguales y no se duplican en el conjunto:

set := Set new.
set add: 1; add: Float pi; add: 3/3; add: 1/3; add: 1.0; yourself
⇒ a Set(1/3 3.141592653589793 1)

Ejemplo 4.14: Set, sin duplicados

Una forma muy práctica de crear una instancia Set, o cualquier otra colección, es crear una matriz dinámica y convertirla con el mensaje #asSet:

{1 . Float pi . 3/3 . 1/3 . 1.0} asSet
⇒ a Set(3.141592653589793 1/3 1)

Ejemplo 4.15: Convertir un array dinámico

Fíjate en los mensajes de conversión alternativos:

{1 . Float pi . 3/3 . 1/3 . 1.0} asOrderedCollection
⇒ an OrderedCollection(1 3.141592653589793 1 1/3 1.0) 

{1 . Float pi . 3/3 . 1/3 . 1.0} asSortedCollection
⇒ a SortedCollection(1/3 1 1 1.0 3.141592653589793)

Para recopilar de forma única la lista de divisores de 30 y 45 (no los divisores comunes):

Set  new 
   addAll: #(1 2 3 5 6 10 15 30) ; 
   addAll: #(1 3 5 9 15 45) ; 
   yourself. 
⇒ a Set(5 10 15 1 6 30 45 2 3 9)

 CuisLogo ¿Cómo recopilarás las letras en las frases ’buenos días’ y ’bonjour’?

Ejercicio 4.15: Letras

Dictionary. Un diccionario es una lista de asociaciones de una clave y un objeto. Por supuesto, una clave es un objeto, pero debe responder a pruebas de igualdad. La mayoría de las veces, se utilizan símbolos como claves.

Para agrupar una lista de colores:

| colors |
colors := Dictionary new.
colors
   add: #red -> Color red;
   add: #blue -> Color blue;
   add: #green -> Color green

Ejemplo 4.16: Diccionario de colores

Hay descripciones más breves:

colors := Dictionary newFrom:
   {#red -> Color red . #blue -> Color blue . #green -> Color green}.
colors := {#red -> Color red . #blue -> Color blue .
   #green -> Color green} asDictionary

Accedes al color mediante símbolos:

colors at: #blue
⇒ Color blue
colors at: #blue put: Color blue darker
colors at: #yellow ifAbsentPut: Color yellow
⇒ association `#yellow -> Colors yellow` added to the dictionary

Hay diferentes formas de acceder al contenido de un diccionario:

colors keys.
⇒ #(#red #green #blue) 
colors keyAtValue: Color green
⇒ #green

Ten cuidado. Los enumeradores clásicos iteran los valores del diccionario:

colors do: [:value | Transcript show:  value; space ]
⇒ (Color r: 1.000 g: 1.000 b: 0.078) (Color r: 0.898 g: 0.000 b: 0.000)...

A veces, realmente es necesario iterar toda la asociación clave-valor:

colors associationsDo: [:assoc | 
   Transcript show: assoc key; space; show: assoc value; cr ]

Hay otras variantes que puedes explorar por tu cuenta.

 CuisLogo Con el apropiado enumerador, ¿cómo puedes modificar los contenidos del diccionario colors para reemplazar sus valores por un bonita cadena capitalizada que represente el nombre del color?

Ejercicio 4.16: Color por nombre

Hay muchas más colecciones por explorar. Ahora ya sabes lo suficiente como para explorar y buscar por ti mismo con el navegador del sistema, y para experimentar con el espacio de trabajo.


Notas al pie

(19)

Por supuesto, pueden insertar un elemento entre otros dos. Sin embargo, una instancia LinkList es más efiiente en este caso.