On Thu, 26 Apr 2001 txporter@mindspring.com wrote:
As a new Squeaker, I am slowly making my way through Mark's book on Squeak.
At the end of chapter 2, there are some exercises, specifically No. 3: Write a piece of workspace code [...] to do the following: (a) Replace all vowels in the string 'Squeak' with dashes.
Like others, I'll presume that returning a new string is kosher.
(b) Compute the average of a set of integers in an array.
I did this like so, but think it is more like "procedural-language speak' and not Smalltalk.
I'm not sure that the issue is primarily procedural vs. OO (as others have said), but Smalltalky vs. transliterated other language :)
Anyone have any more elegant solutions? I particularly do not like the use of the aCount variable.
As others have pointed out, at least implicitly, #do is a pretty blunt instrument. Much joy comes from mastering the enumeration protocal, especially the *ect: methods--#detect:, #select:, #collect:, #reject:, #inject:into:, the combos such as #select:thenCollect: and the "withIndex:" wonders, an so on. Each one is worth learning, and one quickly becomes adept at using them. Manical giggling is optional, but hard to avoid.
The *key* thing, when dealing with string, is to remember that they're collections, indeed, that they are Arrays. So, not only are the a bazillon useful methods in String, and not only, should you peek up the hierachy to see what *other* groovey methods there are, but it's often useful to stop *thinking* of them as strings and treat them just as collections.
Which means, and I don't *think* anyone else has brought this up yet, and which is the whole justifiction for this note, you get to use STREAMS! with them!
And if that's not cause for estatic excitment, well then, uh, you have a much more interesting life than me!
Here's one example: | strm | strm := (ReadWriteStream with: 'Squeak') reset. [strm atEnd] whileFalse: [strm peek isVowel ifTrue: [strm nextPut: $-] ifFalse: [strm next]]. strm contents.
This will modify the orginal string (with the negative consequence for the string literal that Andrew noted). But you can use #do: to iterate over the string: String streamContents: [:strm | 'Squeak' do: [:chr | chr isVowel ifTrue: [strm nextPut: $-] ifFalse: [strm nextPut: chr]]].
(String>>streamContents: is *wonderful* for using WriteStreams to build up strings. Saves some bookkeeping lines.)
(You could also setup a ReadStream on the string. Useful if you need to make decisions based on looking ahead, etc.)
Now, this is nasty compared to the #collect: varient, but it has a *huge* advantage...you can replace the vowels with strings instead of just characters.
E.g., if you replace the ifTrue: block with: [strm nextPut: $-; nextPut: $|]
or the more idomatic: [strm nextPutAll: '-|']
you'll get: 'Sq-|-|-|k'
(Properly managed, streams are generally more speedy for concatenation.)
Cheers, Bijan Parsia.