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. (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. Anyone have any more elegant solutions? I particularly do not like the use of the aCount variable.
aString := 'squeak'. aCount := 1. aString do: [:element | element isVowel ifTrue: [aString at: aCount put: $-]. "Could aString be self?" aCount := aCount +1].
anArray := #(12 14 16 18 20). aSum := 0. aCount := 0. anArray do: [:num | aSum := aSum + num. aCount := aCount +1]. anAverage := aSum / aCount.
Sorry for such a trivial start, but I really want to grok the OO way to do this.
Tom Porter
On Thursday 26 April 2001 12:45, 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. (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. Anyone have any more elegant solutions? I particularly do not like the use of the aCount variable.
aString := 'squeak'. aCount := 1. aString do: [:element | element isVowel ifTrue: [aString at: aCount put: $-]. "Could aString be self?" aCount := aCount +1].
'squeak' collect: [ :ea | ea isVowel ifTrue: [ $- ] ifFalse: [ ea ]]
anArray := #(12 14 16 18 20). aSum := 0. aCount := 0. anArray do: [:num | aSum := aSum + num. aCount := aCount +1]. anAverage := aSum / aCount.
#(12 14 16 18 20) average
anArray := #(12 14 16 18 20). aSum := 0. aCount := 0. anArray do: [:num | aSum := aSum + num. aCount := aCount +1]. anAverage := aSum / aCount.
#(12 14 16 18 20) average
Hi Ned
Seeing your solution makes me reacting, again ;)
I was browsing Array recently and I was really thinking why array should defined methods like average? I see no point to have it there with some others. Because we could have quantil, 3of10Max, 3of10Min......
May be something for SWT?
This also raises the following question: John have you thought about a mechanism that would automatically list all the new/removed methods in comparison to SqC images. This would be really interesting/necessary. May be this could be a cool small project where you could ask for contributors?
Stef
on 4/26/01 9:55 PM, Ned Konz at ned@bike-nomad.com wrote:
On Thursday 26 April 2001 12:45, 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. (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. Anyone have any more elegant solutions? I particularly do not like the use of the aCount variable.
aString := 'squeak'. aCount := 1. aString do: [:element | element isVowel ifTrue: [aString at: aCount put: $-]. "Could aString be self?" aCount := aCount +1].
'squeak' collect: [ :ea | ea isVowel ifTrue: [ $- ] ifFalse: [ ea ]]
Justa quick note ...
Stephane Ducasse wrote:
[...]
John have you thought about a mechanism that would automatically list all the new/removed methods in comparison to SqC images. This would be really interesting/necessary.
Well my name ain't John so pmri, but this task is a nontrivial but not-terribly-difficult application of Joseph Pelrine's "module" work. The idea being, 1. write a script to capture all of an image code in module form ("modularize it") 2. using the modules, write another script to gather a "catalogue" of what's in that image 3. (slightly trickier) export the catalogue, repeat 1. and 2. on the "other" image (e.g., SqC 3.0) 4. write a script to export the diffs between the two catalogues, and there's your answer.
This procedure will seem hauntingly familiar to anyone who's ever scripted to the Team/V api ... or to Envy's poor ol' lame-ass cross-eyed feeble imitation thereof.
Yours etc., replete with dialect prejudice, Paul
At 03:45 PM 4/26/2001 -0400, 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. (b) Compute the average of a set of integers in an array. aString := 'squeak'. aCount := 1. aString do: [:element | element isVowel ifTrue: [aString at: aCount put: $-]. "Could aString be self?" aCount := aCount +1].
anArray := #(12 14 16 18 20). aSum := 0. aCount := 0. anArray do: [:num | aSum := aSum + num. aCount := aCount +1]. anAverage := aSum / aCount.
This will work...
(anArray detectSum: [:num | num]) / anArray size
When it comes to collections...browse the methods in the 'enumerating' message category of the class Collection.
Also, Kent Beck's book "Smalltalk Best Practice Patterns" book talks a great deal about about Collections.
Mark
"txporter" == txporter txporter@mindspring.com writes:
txporter> As a new Squeaker, I am slowly making my way through Mark's book on Squeak. txporter> At the end of chapter 2, there are some exercises, specifically No. 3: txporter> Write a piece of workspace code [...] to do the following: txporter> (a) Replace all vowels in the string 'Squeak' with dashes. txporter> (b) Compute the average of a set of integers in an array.
txporter> I did this like so, but think it is more like "procedural-language speak' and not Smalltalk. Anyone have any more elegant solutions? I particularly do not like the use of the aCount variable.
txporter> aString := 'squeak'. txporter> aCount := 1. txporter> aString do: [:element | element isVowel ifTrue: txporter> [aString at: aCount put: $-]. "Could aString be self?" txporter> aCount := aCount +1].
This one took me about five minutes. I was looking for a way to convert an array of Character to a String... had to stumble across #withAll: ...
String withAll: ('Squeak' asArray collect: [:ch | ch isVowel ifTrue: [$-] ifFalse: [ch]])
Mark, is there a simpler way you had in mind?
txporter> anArray := #(12 14 16 18 20). txporter> aSum := 0. txporter> aCount := 0. txporter> anArray do: [:num | aSum := aSum + num. txporter> aCount := aCount +1]. txporter> anAverage := aSum / aCount.
You're gonna shoot me when you see how easy this is:
anArray := #(12 14 16 18 20). theAverage := (anArray sum) / (anArray size)
Learn to use the method finder. Helps tremendously.
"Randal L. Schwartz" wrote:
You're gonna shoot me when you see how easy this is:
anArray := #(12 14 16 18 20). theAverage := (anArray sum) / (anArray size)
Learn to use the method finder. Helps tremendously.
Yep. In this case, you know the input is #(12 14 16 18 20) and the output will be 16, so you can enter this into the upper left pane of the Method Finder:
#(12 14 16 18 20). 16
This will reveal three methods that will yield that result:
#(12 14 16 18 20) average --> 16 #(12 14 16 18 20) median --> 16 #(12 14 16 18 20) third --> 16
Fun stuff! Someone really needs to write up a beginner's tutorial for the Method Finder.
- Doug Way dway@riskmetrics.com
aString := 'squeak'. aCount := 1. aString do: [:element | element isVowel ifTrue: [aString at: aCount put: $-]. "Could aString be self?" aCount := aCount +1].
Solutions using collect: have been posted, these do the trick.
There is a problem in the preceding code that will not be apparent until you actually use it in a program. This code is not only changing the string, but also the literal 'sqeak' that was stored with the code. If this block were executed repeatedly, this could lead to some pretty obscure bugs.
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.
Thanks to all of you for the interesting responses to my questions.
As regards the bug-inducing practice of mangling the literal 'squeak',
I assume that my assignment of "aString := 'squeak'" merely created a variable, aString that points to a literal, 'squeak'.
If this is the case, then how do I ever assign a variable which was initialized to a literal with a new value:
aString := 'foo'. aString := 'bar'.
if the variable merely points to the literal? Won't this also result in the same kinds of bugs mentioned in previous posts, or have I rather created _two_ literals, or symbols, of which only the second has a active reference, and so the first will be garbage-collected at some point?
Or am I thinking too much?
Thanks again!!
squeak-dev@lists.squeakfoundation.org