Consistency of do: messages in Pharo DataFrame
Different ways to enumerate data series
This post is based on my long and detailed answer to Atharva Khare’s question about the consistency of do: messages in DataSeries class of the Pharo DataFrame project.
All examples will be shown in Transcript:
Transcript open; clear.
To read more about Pharo DataFrame, please visit the project’s GitHub repository and read Data Analysis Made Simple with Pharo DataFrame — also known as the DataFrame booklet.
If you are new to Pharo, be sure to visit http://pharo.org/ and read Pharo by Example.
do: and withIndexDo: in Smalltalk
Collections in Smalltalk respond to a message do:
which accepts aBlock
as argument and applies that block to every element of the collection. aBlock
therefore takes one argument - the element on which it will be applied.
#(a b c d) do: [ :each |
Transcript show: each; cr ]."Result:
a
b
c
d
"
For sequenceable collections, there is also a message withIndexDo:
that can be used to enumerate elements together with their indices. This message accepts a two-argument block: first argument is the element, second argument is the index of that element.
#(a b c d) withIndexDo: [ :each :index |
Transcript show: '[', index asString, '] ', each; cr ]."Result:
[1] a
[2] b
[3] c
[4] d
"
do:, withIndexDo:, and withKeyDo: messages of DataSeries
In order to demonstrate the enumeration of elements of a data series, we will create a simple temperature series inspired by the weather dataset used in the DataFrame booklet:
temperature := DataSeries
withKeys: (
#('01:10' '01:30' '01:50' '02:10' '02:30') collect: #asTime)
values: #(2.4 0.5 -1.2 -2.3 3.2)
name: #temperature.
DataSeries
has message do:
which takes aBlock
as an argument and applies it to every element of the series. The block therefore takes one argument - the element to which it should be applied:
temperature do: [ :each |
Transcript show: each; cr ]."Result:
2.4
0.5
-1.2
-2.3
3.2
"
There is also a message withIndexDo:
which allows us to enumerate elements together with their indices. It takes as argument a two-argument block which expects an element and an index:
temperature withIndexDo: [ :each :index |
Transcript show: '[', index asString, '] ', each asString; cr ]."Result:
[1] 2.4
[2] 0.5
[3] -1.2
[4] -2.3
[5] 3.2
"
And a similar message withKeyDo:
that allows you to enumerate elements together with their keys:
temperature withKeyDo: [ :each :key |
Transcript show: '[', key asString, '] ', each asString; cr ]."Result:
[1:10 am] 2.4
[1:30 am] 0.5
[1:50 am] -1.2
[2:10 am] -2.3
[2:30 am] 3.2
"
Finally, thekeysDo:
message allows us to enumerate only keys. It takes a one-argument block and applies it to each key of the data series.
temperature keysDo: [ :key |
Transcript show: key; cr ]."Result:
1:10 am
1:30 am
1:50 am
2:10 am
2:30 am
"
In fact, it is the same as asking temperature
series for a collection of its keys
and sending do:
message to that collection:
temperature keys do: [ :key |
Transcript show: key; cr ].
Interesting literature on this topic
- Section 2.7. Enumerating values of data series of the DataFrame booklet
- Section Enumerating Elements (p. 136) of Chapter 9. Protocol for All Collection Classes of the Blue Book
- Thread on the mailing list where we discussed the interface for
withIndexDo: