Actually that is the hidden gem on all of this - thinking about the common 
things people do through new eyes, has forced me to learn new things (and that 
feels very compatible with Pharo).

I also thank everyone here for entertaining these questions and hopefully help 
build another way for people to learn Pharo.

Tim

Sent from my iPhone

> On 17 May 2019, at 14:00, Esteban Maringolo <emaring...@gmail.com> wrote:
> 
> 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. Maringolo
> 
> 
>> On Fri, May 17, 2019 at 5:44 AM Sven Van Caekenberghe <s...@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 <rao...@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.wob...@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
>> > 
>> > 
>> 
>> 

Reply via email to