The good thing about these exercises is that you know about new selectors, I didn't know there was an #allButLast and #allButLastDo:.Regards,Esteban A. MaringoloOn Fri, May 17, 2019 at 5:44 AM Sven Van Caekenberghe <sven@stfx.eu> wrote:I would make that
^ String new: gifts size * 10 streamContents: [ :stream |
gifts allButLastDo: [:each |
stream nextPutAll: each; nextPutAll: ', '].
stream nextPutAll: 'and '; nextPutAll: gifts last ]
Your iteration is well done, clear and to the point.
> On 17 May 2019, at 02:44, Richard O'Keefe <raoknz@gmail.com> wrote:
>
> stream := WriteStream on: (String new: gifts size * "estimated size per gift" 10).
> "The number after #new: is the *initial* allocation; the stream will reallocate it
> as needed."
> gifts allButLastDo: [:each |
> stream nextPutAll: each; nextPutAll: ', '].
> stream nextPutAll: 'and '; nextPutAll: gifts last.
> ^stream contents
> Using #allButLastDo: saves making a copy of (most of) gifts.
> How could you find out about these things?
>
> You want to join some strings, so you look for a "join" method in String and you
> will find
>
> join: aCollection
> ^ self class new: (aCollection size * self size) streamContents: [:stream |
> aCollection
> do: [:each | stream nextPutAll: each asString]
> separatedBy: [stream nextPutAll: self]]
>
>
> You might wonder if there is already something close to what you want, so you
> might enter "commas" into Spotter. If you did that, you would find
> Collection>>asCommaStringAnd so that the whole thing is very nearly
> gifts asCommaStringAnd
>
> Just as the concatenation selector #, works with most kinds of sequences,
> so building sequences up using a WriteStream works with most kinds of sequences.
>
> Let's work through a little example. We are just going to build up the string
> 'Quick' one character at a time.
> s := ''.
> s := s , 'Q'. "creates a new string holding 'Q'"
> s := s , 'u'. "creates a new string holding 'Qu'"
> s := s , 'i'. "creates a new string holding 'Qui'"
> s := s , 'c'. "creates a new string holding 'Quic'"
> s := s , 'k'. "creates a new string holding 'Quick'"
>
> You see that building a string of n characters will actually create n new strings,
> all but the last of which will be thrown away, taking O(n**2) time.
>
> Now let's use a stream.
> w := WriteStream on: (String new: 4). "Yes, I know that's too small."
> w nextPutAll: 'Q'. "The stream now holds 'Q...' in its buffer."
> w nextPutAll: 'u'. "The stream now holds 'Qu..' in its buffer."
> w nextPutAll: 'i'. "The stream now holds 'Qui.' in its buffer."
> w nextPutAll: 'c'. "The stream now holds 'Quic' in its buffer."
> s nextPutAll: 'k'. "There is no room left in the buffer, so the stream allocates
> a new buffer twice the size and copies the old one into it.
> Now it has 'Quic....' and it has room.
> The stream now holds 'Quick...' in its buffer."
> s := w contents. "We are asking for the defined elements of the buffer.
> This means s := buffer copyFrom: 1 to: w position."
>
> You see that building a string of n characters this way requires a minimum of
> two strings, the buffer and the final result. The buffer may be periodically
> resized, but growing by doubling means the average cost is still O(n).
>
> Let's time these to get an idea.
> Time millisecondsToRun: [
> |s|
> s := ''.
> 1 to: 10000 do: [:i |
> s := s , i printString].
> s size]
> => 124
> Time millisecondsToRun: [
> |w|
> w := WriteStream on: (String new: 10000).
> 1 to: 10000 do: [:i |
> w nextPutAll: i printString].
> w contents size]
> => 7
>
> This is exactly the reason that Java has both String and StringBuilder.
> The tragedy of Java (well, not the only one) is that they had the example
> of Smalltalk before them, showing very very clearly that the best way to
> handle object to text conversion is to use #printOn: as the primitive,
> not #printString, and they *still* went ahead and did the worse thing.
> (Ruby has even less excuse for privileging to_s.)
>
> There are quite a few books about Smalltalk available as free PDFs from
> the Pharo web site, a wonderful resource. The Blue Book (Smalltalk-80
> The Language and its Implementation) describes streams in Chapter 12.
>
>
> On Fri, 17 May 2019 at 07:21, Roelof Wobben <r.wobben@home.nl> wrote:
> Hello,
>
> Im testing all my solutions with critiz and can solve almost all problems,
>
> Only this one I cannot figure out.
>
> I have this code
> (gifts allButLast
> inject: ''
> into: [ :str :each | str , each , ', ' ]) , 'and ' , gifts last ]
>
> and critiz says I should use a stream .
>
> How can I make this work ?
>
> Roelof
>
>