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