eXept Software AG Logo

Smalltalk/X Webserver

Documentation of class 'Iterator':

Home

Documentation
www.exept.de
Everywhere
for:
[back]

Class: Iterator


Inheritance:

   Object
   |
   +--Collection
      |
      +--Iterator

Package:
stx:libbasic2
Category:
Collections-Sequenceable
Version:
rev: 1.46 date: 2022/10/07 07:58:32
user: stefan
file: Iterator.st directory: libbasic2
module: stx stc-classLibrary: libbasic2

Description:


Occasionally you may have a block that when evaluated can be
treated as a collection -- i.e. it takes another block as parameter,
then applies that to a sequence of values.
Or you have an object which implements some enumeration message (eg. allThingsDo:),
and you want to treat this as a collection.

This goodie wraps the block/target into an object -- an iterator -- which is
part of the collection hierarchy, and therefore inherits a variety of
useful collection-related methods.

See the examples to see how useful that is.

News:
    merged in the class protocol of Enumerator, which is another goody found
    in the open source world. Enumerator does basically the same.
    The comment for Enumerator is:
        Enumerator wraps another object that provides an enumeration method 
        with the same semantics as #do:.  It is an implementation of the
        [external iterator](http://c2.com/cgi/wiki?ExternalIterator) pattern.

        To create an `Enumerator`, send the `#on:selector:` message to the
        `Enumerator` class.  The resulting enumerator responds to all of the
        normal collection enumeration messages.  The selector must be the name
        of a method that provides `do:` semantics for the target object.

        ```
        subclasses := Enumerator on: Collection selector: #allSubclassesDo:.
        (subclasses groupedBy: #superclass) inspect.
        ```

        Some enumeration messages return a collection (`collect:`, `select:`,
        `reject:`, and `groupedBy:`).  By default, the resulting collection
        will be an `OrderedCollection` (or a `Dictionary` whose values are
        `OrderedCollections` in the case of `groupedBy:`).  If you'd like to
        use a different collection type (like `Set` or `Array`), you can use
        the `#on:selector:species:` method instead:

        ```
        MyCollectionObject>>elements
            ^Enumerator on: internalElements selector: #do: species: Set
        ```

[info:]
    NAME            Iterator
    AUTHOR          miw@cs.man.ac.uk (Mario Wolczko)
    FUNCTION        a wrapper for blocks that iterate over collections
    ST-VERSION      4.0 4.1
    PREREQUISITES   
    CONFLICTS
    DISTRIBUTION    world
    VERSION         1
    DATE    18 Jun 1991
    SUMMARY

[organisation:]
    Dept. of Computer Science   Internet:      mario@cs.man.ac.uk
    The University              uucp:        uknet!!man.cs!!mario
    Manchester M13 9PL          JANET:         mario@uk.ac.man.cs
    U.K.                        Tel: +44-61-275 6146  (FAX: 6236)
    ______the mushroom project___________________________________

copyright

COPYRIGHT. The above file is a Manchester Goodie protected by copyright. These conditions are imposed on the whole Goodie, and on any significant part of it which is separately transmitted or stored: * You must ensure that every copy includes this notice, and that source and author(s) of the material are acknowledged. * These conditions must be imposed on anyone who receives a copy. * The material shall not be used for commercial gain without the prior written consent of the author(s). Further information on the copyright conditions may be obtained by sending electronic mail: To: goodies-lib@cs.man.ac.uk Subject: copyright or by writing to The Smalltalk Goodies Library Manager, Dept of Computer Science, The University, Manchester M13 9PL, UK (C) Copyright 1992 University of Manchester For more information about the Manchester Goodies Library (from which this file was distributed) send e-mail: To: goodies-lib@cs.man.ac.uk Subject: help

Class protocol:

instance creation
o  on: aYieldingBlock
return an iterator which calls the yielding block to generate elements.
Notice that 'aBlock asIterator' is the same as 'Iterator on:aBlock'

o  on: collection msg: oneArgSelector
return an iterator which sends oneArgSelector to collection to enumerate it

Usage example(s):

    |i|

     i := Iterator on:#(1 2 3 4 5 6 7) msg:#reverseDo:.
     i do:[:j |
        Transcript showCR:j
     ].

o  on: collection selector: oneArgSelector
return an iterator which sends oneArgSelector to collection to enumerate it

Usage example(s):

    |i|

     i := Iterator on:#(1 2 3 4 5 6 7) msg:#reverseDo:.
     i do:[:j |
        Transcript showCR:j
     ].

o  on: collection selector: oneArgSelector species: aClass
return an iterator which sends oneArgSelector to collection to enumerate it
and returns an instance of aClass when elements are collected.

Usage example(s):

     |i|

     i := Iterator on:#(1 2 3 4 5 6 7 1 2 3 4 5 6 7) selector:#reverseDo: species:OrderedSet.
     i collect:[:j | j * 2].


Instance protocol:

accessing
o  identityIndexOf: anElement
Answer the identity index of anElement within the receiver.
If the receiver does not contain anElement, answer 0.

o  identityIndexOf: anElement ifAbsent: exceptionBlock
Answer the identity index of anElement within the receiver.
If the receiver does not contain anElement, answer the result
of evaluating the exceptionBlock.

o  indexOf: anElement
Answer the index of anElement within the receiver. If the receiver does
not contain anElement, answer 0.

o  indexOf: anElement ifAbsent: exceptionBlock
Answer the index of anElement within the receiver. If the receiver does
not contain anElement, answer the result of evaluating the exceptionBlock.

adding & removing
o  add: anObject
raises an error: Iterators are read-only

o  remove: oldObject ifAbsent: anExceptionBlock
Iterators are read-only.

o  removeIdentical: oldObject ifAbsent: anExceptionBlock
Iterators are read-only.

converting
o  asOrderedCollection
Answer a new instance of OrderedCollection whose elements are the elements of
the receiver. The order in which elements are added depends on the order in
which the receiver enumerates its elements. In the case of unordered collections,
the ordering is not necessarily the same for multiple requests for the conversion.

enumerating
o  collect: aBlock as: aClass
Reimplemented here as Iterator does not support #size.

Usage example(s):

     (Iterator on:[:whatToDo| 'abcd' do:whatToDo]) 
        collect:[:element | element asUppercase] as:OrderedCollection

     (Iterator on:[:whatToDo| 'abcd' do:whatToDo]) 
        collect:[:element | element asUppercase] as:Array

     (Iterator on:[:whatToDo| '1234' do:whatToDo]) 
        collect:[:char | char digitValue] as:ByteArray

o  detectLast: aBlock ifNone: anExceptionValue
evaluate the argument, aBlock for each element in the receiver until
the block returns true; in this case return the element which caused
the true evaluation. The elements are processed in reverse order.
If none of the evaluations returns true, return the value of anExceptionValue

Usage example(s):

     (Iterator on:[:whatToDo| #(1 2 3 4) do:whatToDo]) detectLast:[:n | n odd] ifNone:['sorry']    
     (Iterator on:[:whatToDo| #(2 4 6 8) do:whatToDo]) detectLast:[:n | n odd] ifNone:['sorry']    

o  do: aBlock
evaluate the argument, aBlock for every element in the receiver.
Here, my generator block will iterate and evaluate the block for each

o  findFirst: aBlock ifNone: exceptionalValue
Answer the index of the first element of the receiver
for which aBlock evaluates as true.

o  findLast: aBlock
Answer the index of the last element of the receiver
for which aBlock evaluates as true.

o  keysAndValuesDo: aBlock
Evaluate aBlock with each of the receiver's key/value pairs
(e.g. indexes and elements) as the arguments.

o  reverseDo: aBlock
evaluate the argument, aBlock for each element in reverse order.

inspecting
o  inspectorValueStringInListFor: anInspector
( an extension from the stx:libtool package )
returns a string to be shown in the inspector's list.
Redefined to avoid calling the iterator

printing & storing
o  displayOn: aGCOrStream
what a kludge - Dolphin and Squeak mean: printOn: a stream;

o  printOn: aStream
(comment from inherited method)
append a user readable representation of the receiver to aStream.
The text appended is not meant to be read back for reconstruction of
the receiver. Also, this method limits the size of generated string.

private
o  block

o  block: aBlock

o  species
return the type of collection to be returned by collect, select etc.

o  species: aClass
set the type of collection to be returned by collect, select etc.

queries
o  isEmpty
(comment from inherited method)
return true, if the receiver is empty

o  newSpeciesForCollecting
used when doing collect operations.
Redefined because my size is not known

o  size
(comment from inherited method)
return the number of elements in the receiver.
This is usually redefined in subclasses for more performance.


Examples:


an iterator, generating some numbers
    |i|

    i := 
       [:yield | 
             yield value:0.
             1 to:5 do:[:i | 
                 yield value:i
             ]. 
             yield value:999.
        ] asIterator.

    i do:[:j |
       Transcript showCR:j
    ].
obviously this is an educational example - the same effect has: #(0),(1 to:5),#(999) do:#transcribeCR however, in the iterator example, no actual collection is ever constructed, whereas the other code creates a temporary one. an iterator, simulating a collection of 100 random values:
    |i|

    i := [:yield |
              |rnd|

              rnd := Random new.
              1 to:100 do:[:i | 
                 yield value:(rnd next)
              ] 
         ] asIterator.

    i do:[:j |
       j transcribeCR
    ].
obviously another educational example - the same can be done as: (Random next:100) do:#transcribeCR however, in the iterator example, no actual collection is ever constructed, whereas the other code creates a temporary one. here an example, where iterators really perform better (by not creating a real collection); generate 10Mio random values and count their distribution. Notice that asBag expects a collection, but there is no materialized collection with 10Mio numbers in it:
    |tenMioRandomNumbers counts|

    tenMioRandomNumbers := 
       [:yield |
              1 to:10000000 do:[:i | 
                 yield value:(Random nextIntegerBetween:0 and:10)
              ] 
        ] asIterator.

    counts := tenMioRandomNumbers asBag.
    counts inspect
an iterator, traversing an ad-hoc tree:
    |addToTree tree i|

    'build the sorted tree from a list of numbers...'.
    addToTree := 
       [:tree :newNode |
           newNode value < tree value ifTrue:[
               tree left isNil ifTrue:[
                   tree left:newNode
               ] ifFalse:[
                   addToTree value:(tree left) value:newNode
               ]
           ] ifFalse:[
               tree right isNil ifTrue:[
                   tree right:newNode
               ] ifFalse:[
                   addToTree value:(tree right) value:newNode
               ]
           ].
       ].

    (Random next:30) do:[:rndNr |
       |newNode|
       newNode := { left:nil . value:rndNr . right:nil }.
       tree isNil ifTrue:[
           tree := newNode
       ] ifFalse:[
           addToTree value:tree value:newNode
       ]
    ].

    'define the iterator...'.
    i := [:yield |
              |traverse|

              traverse := [:node |
                   node left notNil ifTrue:[
                       traverse value:node left
                   ].
                   yield value:node value.
                   node right notNil ifTrue:[
                       traverse value:node right
                   ].
              ].
              traverse value:tree.
         ] asIterator.

    'enumerate...'.
    i do:[:j |
       Transcript showCR:j 
    ].
an iterator calling a selector to enumerate elements, here, simulating the collection of subclasses of a class
   |subclasses|
   subclasses := Iterator on:Collection selector:#allSubclassesDo:.
   (subclasses groupedBy:#superclass) inspect.
an iterator, simulating the collection of all classes in the system:
    |i|

    i := [:yield |
              Smalltalk allClassesDo:[:cls | 
                 yield value:cls
              ] 
         ] asIterator.

    i do:[:cls |
       Transcript showCR:cls name
    ].
much like above, one that simulates the collection of all methodNames starting with 'a':
    |i|

    i := [:yield |
              Smalltalk allClassesDo:[:cls |
                 cls methodDictionary keysAndValuesDo:[:nm :mthd |
                   (nm startsWith:$a) ifTrue:[
                      yield value:nm
                    ]
                 ]
              ] 
         ] asIterator.

    i do:[:nm |
       Transcript showCR:nm
    ].
an iterator, simulating a collection of the lines in a file:
    |i|

    i := [:yield |
              |s line|

              s := 'smalltalk.rc' asFilename readStream.
              [s atEnd] whileFalse:[
                 line := s nextLine.
                 yield value:line.
              ].
              s close
         ] asIterator.

    i do:[:j |
       j printNL
    ].
Smalltalk iterators can be used similar to iterators in Python (however, in Python, iterators are streamlike and implicitly created whenever a yield is present in a function, whereas in Smalltalk, they are collection like and explicitly created as such):
   |i coll|

   i := 
       [:yield |
           Transcript showCR:'hello1'.
           yield value:1.
           Transcript showCR:'hello2'.
           yield value:2.
           Transcript showCR:'hello3'.
           yield value:3.
           Transcript showCR:'done'.
       ] asIterator.

   coll do:[:each |
       Transcript showCR:each
   ].


ST/X 7.7.0.0; WebServer 1.702 at 20f6060372b9.unknown:8081; Sat, 27 Jul 2024 08:02:54 GMT