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
>
>