Iterators

Damien Cassou, Stéphane Ducasse and Luc Fabresse http://stephane.ducasse.free.fr

What You Will Learn

Pharo code is Compact!

ArrayList<String> strings = new ArrayList<String>();
for(Person person: persons)
    strings.add(person.name());

is expressed as

strings := persons collect: [ :person | person name ]
strings = persons.stream().map(person -> person.getName())

A First Iterator - collect:

collect: applies the block to each element and returns a collection (of the same kind than the receiver) with the results

  #(2 -3 4 -35 4) collect: [ :each | each abs ]
  > #(2 3 4 35 4)

Another collect: Example

We want to know if each elements is odd or even

#(16 11 68 19) collect: [ :i | i odd ]
>  #(false true false true)

Choose your camp!

  #(16 11 68 19) collect: [ :i | i odd ]

We can also do it that way! (We copied the definition of collect:)

| result |
aCol :=  #(16 11 68 19).
result := aCol species new: aCol size.
1 to: aCollection size do:
    [ :each | result at: each put: (aCol at: each) odd ].
^ result

Part of the Collection Hierarchy

Iterators work polymorphically on the entire collection hierarchy. Below a part of the Collection hierarchy.

Part of the Collection hierarchy.

Think objects!

Basic Iterators Overview

do: an Action on Each Clement

#(16 11 68 19) do: [ :each | Transcript show: each ; cr ]

Here we print each element and insert a carriage return

Results of do:

select: Elements Matching a Criteria

To select some elements, use select:

  #(16 11 68 19) select: [ :i | i odd ]
  > #(11 19)

With Unary Messages, No Block Needed

When a block is just one message, we can pass an unary message selector

#(16 11 68 19) select: [ :i | i odd ]

is equivalent to

#(16 11 68 19) select: #odd

reject: Some Elements Matching a Criteria

To filter some elements, use reject:

#(16 11 68 19) reject:  [ :i | i odd ]
> #(16 68)

detect: The First Elements That...

To find the first element that matches, use detect:

#(16 11 68 19) detect:  [ :i | i odd ]
> 11

detect:ifNone:

To find the first element that matches else return a value, use detect:ifNone:

#(16 12 68 20) detect:  [ :i | i odd ] ifNone: [ 0 ]
> 0

Some Powerful Iterators

Iterating Two Structures

To iterate with:do:

#(1 2 3)
    with:  #(10 20 30)
    do: [ :x :y | Transcript show: (y * x) ; cr ]

0.1. Results of with:do:

with:do: requires two structures of the same length

Use do:separatedBy:

String streamContents: [ :s |
    #('a' 'b' 'c')
        do: [ :each | s << each ]
        separatedBy: [ s << ', ' ]
]
> 'a, b, c'

Grouping Elements

To group elements according to a grouping function: groupedBy:

#(1 2 3 4 5 6 7) groupedBy: #even
> a PluggableDictionary(false->#(1 3 5 7) true->#(2 4 6) )

Flattening Results

How to remove one level of nesting in a collection? Use flatCollect:

#( #(1 2) #(3) #(4) #(5 6)) collect: [ :each | each ]
> #(#(1 2) #(3) #(4) #(5 6)))
#( #(1 2) #(3) #(4) #(5 6)) flatCollect: [ :each | each ]
> #(1 2 3 4 5 6 )

Opening The Box

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

  1 to: self size do: [:i | aBlock value: (self at: i)]

Analysis

Summary

/