|
CS 683 Emerging Technologies: Embracing Change
Spring Semester, 2001
Collections
|
|
|
Previous   
Lecture Notes Index
   Next    
© 2001, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 08-Feb-01
|
|
Contents of Doc 5, Collections
References
Object-Oriented
Design with Smalltalk — a Pure Object Language and its Environment,
Ducasse,
University of Bern, Lecture notes 2000/2001,
http://www.iam.unibe.ch/~ducasse/WebPages/Smalltalk/ST00_01.pdf
Squeak
source code
Collections
Smalltalk
has rich set of collections. Most of them should be familiar to Java
programmers. We will cover some of the important collection classes.
Array
- Fixed
size
- Elements
indexed by integers
Bag
- No
order or indexing
- Repeats
allowed
Dictionary
- Hash
table
- Elements
indexed by any object
Interval
- Finite
arithmetic progression
OrderedCollection
- Growable
array
Set
- No
order, indexing or repeats
SortedCollection
- Sorted
growable array
String
- Fixed
size array of characters
More
Collections
Array2D
- 2
dimensional array
Heap
- A
heap like you studied in data structures
LinkedList
- A
linked list
SharedQueue
- Used
to pass data between processes
Symbol
- String
with unique instances
Text
- Text
that supports fonts, bold etc.
Common
Collection Methods
Some
methods may not be supported by all collection objects. There are a lot of
methods not shown here.
Creation
Creation
methods are sent to Collection classes
new
- Create
a new instance of the receiver with no elements
new:
anInteger
- Fixed
size collections create a collection of size anInteger filled with default
elements
- Variable
sized collections create a collection with capacity anInteger, but no elements
with:
anElement
- Create
a new instance of the receiver with the given element
with:
with:
with:
with: with:
with:
with: with: with:
with:
with: with: with: with:
with:
with: with: with: with: with:
- Create
a new instance of the receiver with the given number of elements
withAll:
aCollection
- Create
a new instance of the receiver with each element of aCollection as an element
in the new collection
Creation
Examples
Expression
|
Result
printed
|
Array
new: 5
|
#(nil
nil nil nil nil)
|
OrderedCollection
new: 5
|
an
OrderedCollection()
|
Array
with: 2 with: 1
|
#(2
1)
|
Bag
with: 1 with: 1 with: 2
|
a
Bag(1 1 2)
|
Set
with: 1 with: 1 with: 2
|
a
Set(1 2)
|
Bag
new
|
a
Bag()
|
OrderedCollection
new
|
an
OrderedCollection()
|
String
new: 5
- Returns
a String with 5 characters
- Each
character has ASCII value 0
Note
the results above are obtained by selecting one line of text at a time in a
workspace and executing it with "print it"
Special
Array Creation
Squeak
has special syntax to make it easy to create arrays. Other versions of
Smalltalk do not have the dynamic array creation shown on the next slide. Some
programmers avoid using this way creating arrays to reduce the effort needed to
port their code other Smalltalks. This dynamic array creation is not part of
the Smalltalk ANSI standard.
Literal
Array Creation
Format:
- #(
element1 element2 ... elementN )
- Created
at compile time
- All
elements are treated as literals
Example
#( 1 2 'cat' ).
Literal
Arrays and Variables
| array x |
x := 'cat'.
array := #( 1 'mouse' x ).
↑array
Returns
#(1 'mouse' #x)
As
the above example shows variables including a variable in a literal array does
not result in the value of the variable being storied in the array. A symbol
for the variable name is stored.
Dynamic
Array Creation
Format:
- {
element1. element2. element3. element4. etc}
- Can
contain variables
- The
value of the variable at the time of creation is used
Examples
| array x |
x := 'cat'.
array := { 1. 'mouse'. x }.
↑array
Returns
#( 1 'mouse' 'cat' )
| array x |
array := { 1. 'mouse'. x }.
x := 'cat'.
↑array
Returns
#(1 'mouse' nil)
Converting
asArray
asBag
asSet
asOrderedCollection
asSortedCollection
asSortedCollection:
aBlock
- Convert
the receiver to the indicated collection
Examples
Expression
|
Result
|
'cat'
asSortedCollection
|
a SortedCollection($a $c $t)
|
#(
3 9 1 4 ) asSortedCollection
|
a SortedCollection(1 3 4 9)
|
#(
1 2 3 2 1) asBag
|
a Bag(1 1 2 2 3)
|
'hi
mom' asBag
|
a Bag($m $m $o $h $i $ )
|
#( 3 9 1 4 ) asSortedCollection: [:x :y | x > y ]
Result
a SortedCollection(9 4 3 1)
#( 3 9 1 4 ) asSortedCollection: [:x :y | x < y ]
Result
a SortedCollection(1 3 4 9)
The
block argument in asSortedCollection: is to return true if the first element
should precede the second one
Accessing
size
- Returns
the current number of element in the collection
capacity
- Returns
the number of elements the collection could hold without growing
at:
indexOrKey
- Return
the element stored at the index or key
- Some
collections want keys (Dictionary) some want indexes
- Replaces
standard array accessing a[k]
at:
indexOrKey put: anElement
- Store
anElement
at
the index or key
- Some
collection wants keys (Dictionary) some want indexes
|
collection |
|
Result
|
collection
:= #( 'a' 'b' 'c' 'd' ).
|
|
collection
size.
|
4
|
collection
capacity
|
4
|
collection
at: 2.
|
'b'
|
collection
at: 1 put: 'cat'.
|
|
collection
printString.
|
'#(''cat''
''b'' ''c'' ''d'')'
|
|
|
collection
:= OrderedCollection new.
|
|
collection
capacity.
|
10
|
collection
size
|
0
|
The
result shown below are the values returned by the statement on the same line as
the result. You do not see the values unless you only execute the code up to
that line.
Adding
Can
not add to a fixed size collection like arrays or strings
Add
methods return the element added to the collection
add:
anElement
- Add
anElement to the end of the receiver (a collection)
addAll:
aCollection
- Add
all elements of aCollection to the end of receiver
| a |
|
Result
on the transcript
|
a
:= OrderedCollection with: $a.
|
|
Transcript
show: a
|
an
OrderedCollection($a )
|
a
add: 'cat'.
|
|
a
add: 5.
|
|
Transcript
show: a.
|
an
OrderedCollection($a ''cat'' 5)
|
a
addAll: 'dog'.
|
|
Transcript
show: a
|
an
OrderedCollection($a ''cat'' 5 $d $o $g)
|
Since
'dog' is a string, which is a collection, addAll: 'dog' adds the characters of
'dog' one at a time to the collection.
Removing
You
can not remove from a fixed size collection like arrays or strings
remove:
anElement
- Remove
anElement from the receiver
- Throw
an exception if anElement is not in the receiver
remove:
anElement ifAbsent: aBlock
- Remove
anElement from the receiver
- Execute
aBlock if anElement is not in the receiver
removeAll:
aCollection
- Remove
all elements in aCollection from the receiver
- Throw
an exception if any element of aCollection is not in the receiver
removeAllFoundIn:
aCollection
- Remove
all elements in aCollection from the receiver
- Ignore
all elements in aCollection not in the receiver
Removing
Examples
|
data result original |
|
Output
in Transcript
|
original
:=
#(
4 3 2 1) asOrderedCollection.
|
|
|
|
data
:= original copy.
|
|
data
remove: 3.
|
|
Transcript
show: data; cr.
|
an
OrderedCollection(4 2 1)
|
|
|
data
:= original copy.
|
|
data
remove: 5 ifAbsent: [].
|
|
Transcript
show: data; cr.
|
an
OrderedCollection(4 3 2 1)
|
|
|
data
:= original copy.
|
|
data
removeAll: #( 1 3).
|
|
Transcript
show: data; cr.
|
an
OrderedCollection(4 2)
|
|
|
data
:= original copy.
|
|
data
removeAllFoundIn: #( 1 6).
|
|
Transcript
show: data; cr.
|
an
OrderedCollection(4 3 2)
|
|
|
result
:= data remove: 4.
|
|
Transcript
show: result; cr.
|
result
|
Testing
isEmpty
includes:
anElement
occurencesOf:
anElement
Examples
Expression
|
Result
|
#(
1 6) isEmpty
|
false
|
'cat'
includes: $o
|
false
|
'mom'
occurrencesOf: $m
|
2
|
#(
1 3 2 4 3) occurrencesOf: 3
|
2
|
Note
the results above are obtained by selecting one line of text at a time in a
workspace and executing it with "print it"
Enumerating
Enumeration:
- Perform
tasks on elements of a collection
- Do
not handle details of accessing each element
Some
languages call this iteration
Example
- Sum of Squares
| sum |
sum := 0.
#( 1 7 2 3 9 3 50) do: [:each | sum := sum + each squared].
↑sum
do:
iterates or enumerates through the elements of the array
We
could use a normal loop construct like:
| data sum |
data := #( 1 7 2 3 9 3 50).
sum := 0.
1 to: data size do: [:each | sum := sum + (data at: each) squared].
sum
Loop
Construct Verses Enumeration
The
loop construct:
- Is
more work
- Assumes
the collection is ordered
- Will
not work will bags, sets, and dictionaries
Enumeration
is:
- Less
work
- More
general
- Just
as fast
Use
Enumeration over explicit loop constructs
Basic
Enumeration for all Collections
do:
aBlock
|
Evaluate
aBlock with each of the receiver's elements as the argument.
|
select:
aBlock
|
Evaluate
aBlock with each of the receiver's elements as the argument. Collect into a new
collection like the receiver, only those elements for which aBlock evaluates to
true. Answer the new collection.
|
reject:
aBlock
|
Evaluate
aBlock with each of the receiver's elements as the argument. Collect into a new
collection like the receiver only those elements for which aBlock evaluates to
false. Answer the new collection.
|
collect:
aBlock
|
Evaluate
aBlock with each of the receiver's elements as the argument. Collect the
resulting values into a collection like the receiver. Answer the new collection.
|
detect:
aBlock
|
Evaluate
aBlock with each of the receiver's elements as the argument. Answer the first
element for which aBlock evaluates to true. Signal an Error if none are found.
|
inject:
initialValue into: binaryBlock
|
Accumulate
a running value associated with evaluating the argument, binaryBlock, with the
current value of the argument, thisValue, and the receiver as block arguments.
|
do:
do:
aBlock
- Evaluate
aBlock with each of the receiver's elements as the argument.
'this is an example' do:
[:each |
each isVowel ifTrue:[Transcript show: each]]
Result
in Transcript
iiaeae
keysAndValuesDo:
aBlock
Defined
for keyed collections only (no bags & sets)
Sometimes
one needs the element of a collection and the index of the element
'this is an example' keysAndValuesDo:
[:key :value |
value isVowel
ifTrue:
[Transcript
show: key;
tab;
show: value;
cr]]
Result
in Transcript
3
|
i
|
6
|
i
|
9
|
a
|
12
|
e
|
14
|
a
|
18
|
e
|
Some
Fun
Can
you parse this program?
What
does each message do?
Transcript
show: 'Digit';
tab;
show: 'Frequency';
cr.
100 factorial asString asBag sortedElements do:
[:each |
Transcript
show: each key;
tab;
show: each value;
cr]
Output
In Transcript
Digit
|
Frequency
|
0
|
30
|
1
|
15
|
2
|
19
|
3
|
10
|
4
|
10
|
5
|
14
|
6
|
19
|
7
|
7
|
8
|
14
|
9
|
20
|
select:
aBlock
Return
a new collection with the elements of the receiver that make the block evaluate
to true
Example
| result |
result := 'this is an example' select: [:each | each isVowel ].
↑result
Returned
Value
'iiaeae'
reject:
aBlock
Return
a new collection with the elements of the receiver that make the block evaluate
to false
Example
|
result |
result
:= #( 1 5 2 3 6) reject: [:each | each even ].
↑result
Returned
Value
#(1 5 3)
collect:
aBlock
Collects
the return values of aBlock into new collection
Examples
| result |
result := #( 1 2 3 4 5) collect: [:each | each squared ].
↑result
Returned
Value
#(1 4 9 16 25)
| result |
result := 'hi mom' collect: [:each | each asUppercase ].
↑result
Returned
Value
'HI MOM'
detect:
aBlock
Returns
the first element in the receiver that makes aBlock evaluate to true
#( 1 7 2 3 9 3 50) detect: [:each | each > 8]
Returns
9
inject:
thisValue into: binaryBlock
Accumulates
a running value
inject:into
is confusing the first time you see it.
Compute
Sum of Collection's Elements
#( 1 2 3 4)
inject: 0
into: [:partialSum :number | partialSum + number]
Compute
Product of Collection's Elements
#( 1 2 3 4)
inject: 1
into: [:partialProduct :number | partialProduct * number]
Count
the Vowels in a String
'hi mom' inject: 0 into:
[:partial :each |
each isVowel
ifTrue:[partial + 1]
ifFalse:[partial]]
Note
the first two examples are used in Smalltalk code, there are easier ways to
count vowels
Detailed
inject:into: Example
Transcript
clear;
show: 'Partial';
tab;
show: 'Number';
cr.
#( 1 2 3 4 5) inject: 0 into:
[:partialSum :number |
Transcript
show: partialSum;
tab;
show: number;
cr.
partialSum + number.]
Result
in Transcript
Partial
|
Number
|
0
|
1
|
1
|
2
|
3
|
3
|
6
|
4
|
10
|
5
|
Example
- Computing Sum of Squares
C++
like Code
| data sum |
data := #( 1 7 2 3 9 3 50).
sum := 0.
1 to: data size do: [:each | sum := sum + (data at: each) squared].
sum
With
do:
| sum |
sum := 0.
#( 1 7 2 3 9 3 50) do: [:each | sum := sum + each squared].
sum
With
inject:into
#( 1 7 2 3 9 3 50) inject: 0 into: [:sum :each | sum + each squared]
More
There
is a lot more to the collection classes in Squeak. Use the System browser to
explore. We will come back to some of the classes, but will move on for now.
Try the exercises on the next page.
Exercises
1.
Show the order of evaluation of the subexpressions in the following:
- 9
/ 3 between: 10 - 2 squared and: 12.5 ceiling + 3
2.
What happens when you select the word 'size' (without the quotes) in a
workspace and type alt-m
on a PC (command-m
on Mac)?
3.
What happens when you evaluate the following expressions?
- 'cat'
inspect
- 'cat'
class
- 'cat'
class inspect
- 'cat'
class browse
- 'cat'
class organization inspect
4.
Find the method findTokens: and read its comment. From the comment explain what
the following will return.
- 'this,it
a;test' findTokens: '; ,'
5.
What class defines the method shuffled? What does it do?
6.
What method in the string class to tells you if one string contains another?
7.
Write Smalltalk code to copy the 3rd to the 5th element in #( 2 4 1 3 5 ) to a
new array.
8.
Identify the messages and receivers in the following expression. What is the
class of each receiver?
- (1
to: 20 by: 3) at: 4
9.
What is the result of evaluation the expression:
- (1
to: 20 by: 3) asArray
10.
Write Smalltalk code to take the vowels in 'this is an exercise' and place them
in an OrderedCollection.
11.
Write Smalltalk code to produce a list of the integers 1, 2, ..., 10 in random
order.
Copyright ©, All rights reserved.
2001 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA.
OpenContent license defines the copyright on this document.
Previous   
visitors since 08-Feb-01
   Next