Very nice methods
Sometimes you just want to do something for all subsets of a particular collection (including the "empty" and "all" subsets). The typical stuff that comes to mind is to count from 0 to 2^collection size - 1 (heh, or collection size mersenne), then sift through the bits and add stuff at the proper index when the proper bit is 1, etc. You get the idea.
The other day I needed to take the products of all possible subsets of a collection of integers. I had already implemented the bit-sifting approach when I realized I had sinned against my own principles by having been too clever when it had not been necessary.
So I dumped all that bit-sifting code and, instead, followed what we actually do. Consider the collection $A to: $Z, and all its possible substrings (e.g.: 'ABCZ', 'JRTXY', 'F', etc). Clearly, all the substrings of $A to: $Z are all the possible substrings of $B to: $Z, once prefixed with $A and once not prefixed with $A.
The same argument applies all the way down to $Z to: $Z. So all the number iteration becomes process stack recursion in terms of sending messages, without any of the bit-sifting arithmetic nonsense.
So, for my product problem, I implemented these methods in SequenceableCollection:
- allProductsTimes: aNumber
do: aBlock
- self
- allProductsTimes: aNumber
startingAt: 1
do: aBlock
- allProductsTimes: aNumber
startingAt: anIndex
do: aBlock
- anIndex > self size
- ifTrue: [aBlock value: aNumber]
- ifFalse:
- [self
- allProductsTimes: aNumber
startingAt: anIndex + 1
do: aBlock.
- allProductsTimes: aNumber * (self at: anIndex)
startingAt: anIndex + 1
do: aBlock]
Isn't that absolutely beautiful?
Since the elements of the collection could be polynomials or matrices, then I can't assume the empty product is 1. The first method used to refer to the value of the empty product. But since the second method multiplies everything that follows by something that is given, these new methods ended having more functionality for free. Fantastic, fantastic.
