how to do nested loops of variable depth?

Baveco, Hans J.M.Baveco at Alterra.wag-ur.nl
Wed Dec 19 13:20:14 UTC 2001


It looks like this solution is exactly what I had hoped for! Thanks!

I don't need to actually create the collection of all combinations, just
want to iterate over all possible combinations. That is for me useful in a
sort of model sensitivity-analysis: I select a variable number of parameters
and define for each parameter a range of values, and then run the model with
each possible combination of parameter values.

Thanks again,
Hans


-----Original Message-----
From: Boris_Gaertner at msg.de
To: squeak-dev at lists.squeakfoundation.org
Sent: 19-12-01 13:36
Subject: RE: how to do nested loops of variable depth?


Hello, 

the attached class (CollectionCombinator.st) 
should do what you want to do. 
To compute the cartesian product (that is what you want 
to do!) I set up an array of streams. A recursive method is 
used to build all elements of the carthesian product. 
The solution is certainly not easy to understand, but it is 
written with one design goal in mind: It does not construct 
a lot of partial results. 

A question to you: Do you really need the collection of all
combinations? 
You know that even for a small number of small collections the size of 
the cartesian product  will be huge. 

You want to process all elements of the cartesian product. OK. To do 
that, you do not need to put all these elements into a collection. 
You can process an element immediately after construction. To do that, 
you can use a block that is called once for every constructed tuple. 

Look at this: (CollectionCombinator2.st) 




A final note: 

In Smalltalks with full block closures you can do the following: 


  | result arrays sizeOfResult streams block | 


arrays := OrderedCollection new. 
arrays add: #(#a #b); 
       add: #(1 2 3 4); 
       add: #('w' 'x' 'y' 'z'). 
sizeOfResult := 
   arrays inject: 1 into: 
          [:prod :array | prod * array size]. 
streams := arrays collect: 
            [:a | ReadStream on: a]. " This is an OrderedCollection of
Streams " 

result := OrderedCollection new: sizeOfResult. 
block := 
 [:r :tupel :myIdx :allStreams | 

 [myIdx = allStreams size 
          ifTrue: [1 to: allStreams size do: 
                   [:i | tupel at: i put: (allStreams at: i) peek]. 
                         r addLast: tupel shallowCopy] 
         ifFalse:  [block  value: r value: tupel value: myIdx + 1 value:
allStreams]. 
        (allStreams at: myIdx) next.     
        (allStreams at: myIdx) atEnd 
 ] 
 whileFalse: []. 
 (allStreams at: myIdx) reset. 
   r   
  ]. 
 block value: result 
                       value: (Array new: streams size) " this is a
buffer " 
                            value: 1 
                            value: streams. 

result 


Here, a block is given a name and the block name is used 
within the block itself. This is of course a recursive call. 
When you evaluate this in a workspace, 
Squeak 3.1 will show you an error notification that states that 
you are not allowed evaluate a block that is currently evaluated. 
(In other words: You cannot use a named block as a recursive 
procedure.) In some Smalltalks you can do that. 




Cheers 
Boris Gärtner


mailto: Boris_Gaertner at msg.de
 <<CollectionCombinator.st>>  <<CollectionCombinator2.st>> 




More information about the Squeak-dev mailing list