Consistency of do: messages in Pharo DataFrame

Different ways to enumerate data series

Oleksandr Zaitsev
May 15 · 3 min read

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 ].

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 ].

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 ].

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 ].

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 ].

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 ].

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

  1. Section 2.7. Enumerating values of data series of the DataFrame booklet
  2. Section Enumerating Elements (p. 136) of Chapter 9. Protocol for All Collection Classes of the Blue Book
  3. Thread on the mailing list where we discussed the interface for withIndexDo:

Oleksandr Zaitsev

Written by

Relais thèse at Inria Lille. Pharo contributor and GSoC org from Pharo Consortium. MSc. in Data Science, BSc. in Informatics.