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