The Collections-
class categories are the most prolific,
there are 7 of them gathering 46 classes.
The category Collections-Abstract
groups classes that are
said to be abstract. An abstract class cannot be instantiated,
its behavior is declared but not completely implemented. It is the
responsibility of its subclasses to implement the missing part of the
behavior.
An abstract class is useful to establish a set of polymorphic methods which each of its concrete subclasses is expected to specialize. This captures and communicates our intent.
Observe how the important do:
method is declared
but not implemented:
Collection>>do: aBlock "Evaluate aBlock with each of the receiver's elements as the argument." self subclassResponsibility
Then observe how two different Collection
subclasses
implement it:
OrderedCollection>>do: aBlock firstIndex to: lastIndex do: [ :index | aBlock value: (array at: index) ]
and:
Dictionary>>do: aBlock super do: [:assoc | aBlock value: assoc value]
Two important groups of collections must be distinguished: collections with a fixed size and collections with a variable size.
Collection of fixed size. Such collections are gathered in
the category Collections-Arrayed
. The most notable one is
Array
, its size – the number of elements it can hold – is
set when creating the instance. Once instantiated, you can neither add nor
delete elements to an array.
There are different ways to create Array
instance:
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"
Array array1
and array1b
are bit
different. The former one is created and filled with its contents during the
compile time of the code, the consequence is it can only be filled
with literal elements such as integer, float, or string. The latter one is
created at the execution time of the code, it can be filled with elements
instantiated at the execution time as Fraction
or
Point
instances.
You can access elements with an important variety of messages:
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
Use the System Browser to discover alternative ways to access elements of a collection.
What is the appropriate message to access the first 2 elements of the
array1
collection?
You can’t add or remove an element, though:
array1 add: 'Orange' ⇒ Error: 'This message is not appropriate for this object' array1 remove: 'Apple' ⇒ Error: 'This message is not appropriate for this object'
Nevertheless, it is possible to fill at once an array:
Fill every element in
array1
with ’kiwi’ all at once?
Collection of variable size. Such collection are gathered in
several class categories: Collections-Unordered
,
Collections-Sequenceable
, etc. They represent the most common
collections.
OrderedCollection
is a notable one. Its elements are ordered:
elements are added one after the other in sequence19. Its size is
variable depending on added or removed elements.
coll1 := {2 . 'Apple' . 2@1 . 1/3 } asOrderedCollection coll2 := OrderedCollection with: 2 with: 'Apple' with: 2@1 with: 1/3 coll3 := OrderedCollection ofSize: 4
The access to elements is identical to an Array
instance, but dynamic collections allow you to add and remove elements:
coll1 add: 'Orange'; yourself ⇒ an OrderedCollection(2 'Apple' 2@1 1/3 'Orange') coll1 remove: 2@1; yourself ⇒ an OrderedCollection(2 'Apple' 1/3)
How to add ’Orange’ after ’Apple’ in
coll1
?
Set. Set
is an unordered collection without duplicated
elements. The order of the elements is not guaranteed, though. Observe
how pi is the first element of the set:
set := Set new. set add: 1; add: Float pi; yourself ⇒ a Set(3.141592653589793 1)
Nonduplicates are guaranteed at least, even with a number of different
types. Observe how 1
, 3/3
and 1.0
are considered equal and not duplicated in the set:
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)
A very handy way to create a Set
instance, or any other
collection is to create a dynamic array and convert it with the
#asSet
message:
{1 . Float pi . 3/3 . 1/3 . 1.0} asSet ⇒ a Set(3.141592653589793 1/3 1)
Observe the alternate conversion messages:
{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)
To uniquely collect the divisors list of 30 and 45 (not the common divisors):
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)
How will you collect the letters in the sentences ’buenos días’ and ’bonjour’?
Dictionary. A dictionary is a list of associations between a key and an object. Of course, a key is an object, but it must respond to equality tests. Most of the time, symbols are used as keys.
To compile a list of colors:
| colors | colors := Dictionary new. colors add: #red -> Color red; add: #blue -> Color blue; add: #green -> Color green
There are shorter descriptions:
colors := Dictionary newFrom: {#red -> Color red . #blue -> Color blue . #green -> Color green}. colors := {#red -> Color red . #blue -> Color blue . #green -> Color green} asDictionary
You access color by symbols:
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
There are different ways to access a dictionary’s contents:
colors keys. ⇒ #(#red #green #blue) colors keyAtValue: Color green ⇒ #green
Beware. The classic enumerators iterate the values of the dictionary:
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)...
Sometimes, you really need to iterate the whole key-value association:
colors associationsDo: [:assoc | Transcript show: assoc key; space; show: assoc value; cr ]
There are other variants to explore by yourself.
With an appropriate enumerator, how will you edit the contents of the
colors
dictionary to replace its values with a nicely capitalized string representing the name of the color?
There are many more collections to explore. You now know enough to explore and to search by yourself with the System Browser, and to experiment with the Workspace.
Of course you can
insert an element between two elements. However, a LinkList
instance is more efficient for this use case.