join

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
60 messages Options
123
Reply | Threaded
Open this post in threaded view
|

join

keith1y
Entirely against my will, I once worked in a perl shop, and I noticed
that perlites liked joining things.

Whenever I find myself wanting to join a bunch of items together (e.g.
to make a path) I am never satisfied with the result and so I took a
look at the Collections/String classes to see whether anything fitted
nicely.


I came up with

SequencableCollection>>join: aCollection

    ^ self class streamContents: [ :stream |
        aCollection
            do: [ :each | stream nextPut: each ]
            separatedBy: [ stream nextPutAll: self ] ]


and

Character>>join: aCollectionOfStrings

    ^ self class streamContents: [ :stream |
        aCollectionOfStrings
            do: [ :each | stream nextPutAll: each ]
            separatedBy: [ stream nextPut: self ] ]

and

Collection>>joinWith: aCollection

aCollection join: self

----
This now allows
 
(Array with: 1 with: 2) join: (Array with: 3 with: 4 with: 5)
$/ join: (Array with: 'Hello' with: 'my' with: 'World').

any thoughts? I am curious as to why #join: hasn't made it into the core
image, and if it were to how would it happen?

Keith

               
___________________________________________________________
The all-new Yahoo! Mail goes wherever you go - free your email address from your Internet provider. http://uk.docs.yahoo.com/nowyoucan.html

Reply | Threaded
Open this post in threaded view
|

Re: join

timrowledge

On 14-Sep-06, at 4:57 PM, Keith Hodges wrote:

> Entirely against my will, I once worked in a perl shop, and I  
> noticed that perlites liked joining things.
>
> Whenever I find myself wanting to join a bunch of items together  
> (e.g. to make a path) I am never satisfied with the result and so I  
> took a look at the Collections/String classes to see whether  
> anything fitted nicely.

Well, first point is that you shouldn't make paths like that.  
Filenames are *not* strings. If you use constructs like
FileDirectory default directoryNamed:'foo'
you'd get a properly (well, as properly as we can manage right now)  
made file directory object with a properly formed pathname. It would  
handle platform path separator issues, for example.


tim
--
tim Rowledge; [hidden email]; http://www.rowledge.org/tim
The generation of random numbers is too important to be left to chance.



Reply | Threaded
Open this post in threaded view
|

Re: join

keith1y
In answer to your first point, I was not intending to use join for that,
it was 'only' an example.

To be honest I dont think much of Squeak's directory/path classes I
contributed to a nice ruby 'Path' module about 5 years ago which was
quite elegant.


Keith

               
___________________________________________________________
To help you stay safe and secure online, we've developed the all new Yahoo! Security Centre. http://uk.security.yahoo.com

Reply | Threaded
Open this post in threaded view
|

Re: join

Klaus D. Witzel
In reply to this post by keith1y
Hi Keith,

on Fri, 15 Sep 2006 01:57:52 +0200, wrote:
...
> any thoughts? I am curious as to why #join: hasn't made it into the core  
> image, and if it were to how would it happen?

There are several reasons for the absence of #join:

- the most important one is, that nobody needs it (or else you would have  
found it). Imagine Pearl with the full Squeak Stream hierarchy, why use  
join?

- streaming is more flexible when you keep control, it allows better  
maintainable and adaptable code.

- #join: must be implemented in *base* classes in order to work. String  
streamContents: [:...] must not be implemented anywhere, it's always where  
want need it.

Just my CHF 0.05

/Klaus

> Keith


Reply | Threaded
Open this post in threaded view
|

Re: join

Avi  Bryant

On Sep 14, 2006, at 6:25 PM, Klaus D. Witzel wrote:

> Hi Keith,
>
> on Fri, 15 Sep 2006 01:57:52 +0200, wrote:
> ...
>> any thoughts? I am curious as to why #join: hasn't made it into  
>> the core image, and if it were to how would it happen?
>
> There are several reasons for the absence of #join:
>
> - the most important one is, that nobody needs it (or else you  
> would have found it). Imagine Pearl with the full Squeak Stream  
> hierarchy, why use join?

Sure we need it.  At Smallthought, we have a package of utility  
methods that includes:

SequencableCollection>>joinTokens: aString
        ^ String streamContents:
                [:s |
                self do: [:ea | s nextPutAll: ea asString] separatedBy: [s  
nextPutAll: aString]]

Looking through my sends to it, the argument is always either ' ' or  
', ', so #joinedWithSpaces and #joinedWithCommas would probably be  
sensible methods to have too.

Avi

Reply | Threaded
Open this post in threaded view
|

Re: join

Klaus D. Witzel
Hi Avi,

on Fri, 15 Sep 2006 03:31:02 +0200, wrote:

> On Sep 14, 2006, at 6:25 PM, Klaus D. Witzel wrote:
>> Hi Keith,
>> on Fri, 15 Sep 2006 01:57:52 +0200, wrote:
>> ...
>>> any thoughts? I am curious as to why #join: hasn't made it into the  
>>> core image, and if it were to how would it happen?
>>
>> There are several reasons for the absence of #join:
>>
>> - the most important one is, that nobody needs it (or else you would  
>> have found it). Imagine Pearl with the full Squeak Stream hierarchy,  
>> why use join?
>
> Sure we need it.  At Smallthought, we have a package of utility methods  
> that includes:
>
> SequencableCollection>>joinTokens: aString
> ^ String streamContents:
> [:s |
> self do: [:ea | s nextPutAll: ea asString] separatedBy: [s nextPutAll:  
> aString]]
>
> Looking through my sends to it, the argument is always either ' ' or ',  
> ', so #joinedWithSpaces and #joinedWithCommas would probably be sensible  
> methods to have too.

No nitpicking intended, the question and the answer was from the  
perspective why Squeak doesn't have it.

But you're right, one counterexample brings my nobody case to fall :)

/Klaus

> Avi


Reply | Threaded
Open this post in threaded view
|

Re: join

keith1y
In reply to this post by Avi Bryant
Thanks Avi,

thats just the method that I was looking for! So please let's get it
added to the base image ;-)

This request is somewhat academic since I am stuck in 3.8 for a while
until Magma supports 3.9.

Keith

>>
>> - the most important one is, that nobody needs it (or else you would
>> have found it). Imagine Pearl with the full Squeak Stream hierarchy,
>> why use join?
>
> Sure we need it.  At Smallthought, we have a package of utility
> methods that includes:
>
> SequencableCollection>>joinTokens: aString
>     ^ String streamContents:
>         [:s |
>         self do: [:ea | s nextPutAll: ea asString] separatedBy: [s
> nextPutAll: aString]]
>
> Looking through my sends to it, the argument is always either ' ' or
> ', ', so #joinedWithSpaces and #joinedWithCommas would probably be
> sensible methods to have too.
>
> Avi
>
>


       
       
               
___________________________________________________________
All new Yahoo! Mail "The new Interface is stunning in its simplicity and ease of use." - PC Magazine
http://uk.docs.yahoo.com/nowyoucan.html

Reply | Threaded
Open this post in threaded view
|

Re: join

tblanchard
In reply to this post by Avi Bryant
Poking around a frequently used image I find:

String>>splitOn: aString
and
SequenceableCollection>>joinOn: aString

And I use them quite a bit when processing input.


On Sep 14, 2006, at 6:31 PM, Avi Bryant wrote:

> On Sep 14, 2006, at 6:25 PM, Klaus D. Witzel wrote:
>
>> Hi Keith,
>>
>> on Fri, 15 Sep 2006 01:57:52 +0200, wrote:
>> ...
>>> any thoughts? I am curious as to why #join: hasn't made it into  
>>> the core image, and if it were to how would it happen?
>>
>> There are several reasons for the absence of #join:
>>
>> - the most important one is, that nobody needs it (or else you  
>> would have found it). Imagine Pearl with the full Squeak Stream  
>> hierarchy, why use join?
>
> Sure we need it.  At Smallthought, we have a package of utility  
> methods that includes:
>
> SequencableCollection>>joinTokens: aString
> ^ String streamContents:
> [:s |
> self do: [:ea | s nextPutAll: ea asString] separatedBy: [s  
> nextPutAll: aString]]
>
> Looking through my sends to it, the argument is always either ' '  
> or ', ', so #joinedWithSpaces and #joinedWithCommas would probably  
> be sensible methods to have too.
>
> Avi
>


Reply | Threaded
Open this post in threaded view
|

Re: join

Ramon Leon-4
In reply to this post by keith1y
>> Sure we need it.  At Smallthought, we have a package of utility
>> methods that includes:
>>
>> SequencableCollection>>joinTokens: aString
>>     ^ String streamContents:
>>         [:s |
>>         self do: [:ea | s nextPutAll: ea asString] separatedBy: [s
>> nextPutAll: aString]]
>>
>> Looking through my sends to it, the argument is always either ' ' or
>> ', ', so #joinedWithSpaces and #joinedWithCommas would probably be
>> sensible methods to have too.
>>
>> Avi

Funny, one of the first extension methods I added when I learned
Smalltalk, was join as well, I'm still amazed it isn't already there.  I
got tired of typing out the stream version, and in all but one case, I
was also joining on either ' ' or ', '.

Collection>>join: aString
     ^String streamContents: [:stream |
         self do: [:each | stream nextPutAll: each]
              separatedBy: [stream nextPutAll: aString]]

Avi, is there a reason you chose SequencableColleciton over just
Collection, I'm curious if I've put mine in the wrong place, and the
implications of doing so?


Reply | Threaded
Open this post in threaded view
|

Re: join

Ramon Leon-4
In reply to this post by tblanchard
> Poking around a frequently used image I find:
>
> String>>splitOn: aString
> and
> SequenceableCollection>>joinOn: aString
>
> And I use them quite a bit when processing input.

Care to share your #splitOn:, my #split: was just a synonym for
#findTokens: which I recently realized didn't do what I thought it did.


Reply | Threaded
Open this post in threaded view
|

Re: join

tblanchard
OK

splitOn: aString

        | idx lastIdx |
        idx := lastIdx := 1.

        ^Array streamContents:
        [:s |
                [idx <= self size] whileTrue:
                [
                        idx := self findString: aString startingAt: lastIdx.
                        idx = 0 ifTrue: [idx := self size + 1].
                        s nextPut: (self copyFrom: lastIdx to: idx-1).
                        lastIdx := idx + aString size.
                ]
        ]




On Sep 14, 2006, at 8:48 PM, Ramon Leon wrote:

>> Poking around a frequently used image I find:
>> String>>splitOn: aString
>> and
>> SequenceableCollection>>joinOn: aString
>> And I use them quite a bit when processing input.
>
> Care to share your #splitOn:, my #split: was just a synonym for  
> #findTokens: which I recently realized didn't do what I thought it  
> did.
>
>


Reply | Threaded
Open this post in threaded view
|

Re: join

Avi  Bryant
In reply to this post by Ramon Leon-4

On Sep 14, 2006, at 8:44 PM, Ramon Leon wrote:

> Avi, is there a reason you chose SequencableColleciton over just  
> Collection, I'm curious if I've put mine in the wrong place, and  
> the implications of doing so?

Only that the output is deterministic for a SequenceableCollection  
and not for, say, a Set.

Avi

Reply | Threaded
Open this post in threaded view
|

Re: join

Ramon Leon-4
In reply to this post by tblanchard
> splitOn: aString
>
>     | idx lastIdx |
>     idx := lastIdx := 1.
>
>     ^Array streamContents:
>     [:s |
>         [idx <= self size] whileTrue:
>         [
>             idx := self findString: aString startingAt: lastIdx.
>             idx = 0 ifTrue: [idx := self size + 1].
>             s nextPut: (self copyFrom: lastIdx to: idx-1).
>             lastIdx := idx + aString size.
>         ]
>     ]

Cool, thanks.


Reply | Threaded
Open this post in threaded view
|

Re: join

stephane ducasse-2
In reply to this post by keith1y
Oscar and Damien did an implementation of join and split and I would  
really like to ease
perl people and include such protocols in the next release (with tests)
Now if would be nice to have a discussion on the implementations

http://bugs.impara.de/view.php?id=4874

> I came up with
>
> SequencableCollection>>join: aCollection
>
>    ^ self class streamContents: [ :stream |
>        aCollection
>            do: [ :each | stream nextPut: each ]
>            separatedBy: [ stream nextPutAll: self ] ]
>
>
> and
>
> Character>>join: aCollectionOfStrings
>
>    ^ self class streamContents: [ :stream |
>        aCollectionOfStrings
>            do: [ :each | stream nextPutAll: each ]
>            separatedBy: [ stream nextPut: self ] ]
>
> and
>
> Collection>>joinWith: aCollection
>
> aCollection join: self
>
> ----
> This now allows
> (Array with: 1 with: 2) join: (Array with: 3 with: 4 with: 5)
> $/ join: (Array with: 'Hello' with: 'my' with: 'World').
>
> any thoughts? I am curious as to why #join: hasn't made it into the  
> core image, and if it were to how would it happen?
>
> Keith
>
>
> ___________________________________________________________ The all-
> new Yahoo! Mail goes wherever you go - free your email address from  
> your Internet provider. http://uk.docs.yahoo.com/nowyoucan.html
>


Reply | Threaded
Open this post in threaded view
|

Re: join

stephane ducasse-2
In reply to this post by keith1y
hi guys

could you sit down and propose a cool set of names and implementation  
and we include it in 3.10

http://bugs.impara.de/view.php?id=4874


Reply | Threaded
Open this post in threaded view
|

Re: join

tblanchard
In reply to this post by stephane ducasse-2
I'll just mention that mine are modeled on the NextStep routines

NSString>>componentsSeparatedByString:
NSArray>>componentsJoinedByString:

they behave exactly the same way.




On Sep 15, 2006, at 8:37 AM, stephane ducasse wrote:

> Oscar and Damien did an implementation of join and split and I  
> would really like to ease
> perl people and include such protocols in the next release (with  
> tests)
> Now if would be nice to have a discussion on the implementations
>
> http://bugs.impara.de/view.php?id=4874
>
>> I came up with
>>
>> SequencableCollection>>join: aCollection
>>
>>    ^ self class streamContents: [ :stream |
>>        aCollection
>>            do: [ :each | stream nextPut: each ]
>>            separatedBy: [ stream nextPutAll: self ] ]
>>
>>
>> and
>>
>> Character>>join: aCollectionOfStrings
>>
>>    ^ self class streamContents: [ :stream |
>>        aCollectionOfStrings
>>            do: [ :each | stream nextPutAll: each ]
>>            separatedBy: [ stream nextPut: self ] ]
>>
>> and
>>
>> Collection>>joinWith: aCollection
>>
>> aCollection join: self
>>
>> ----
>> This now allows
>> (Array with: 1 with: 2) join: (Array with: 3 with: 4 with: 5)
>> $/ join: (Array with: 'Hello' with: 'my' with: 'World').
>>
>> any thoughts? I am curious as to why #join: hasn't made it into  
>> the core image, and if it were to how would it happen?
>>
>> Keith
>>
>>
>> ___________________________________________________________ The  
>> all-new Yahoo! Mail goes wherever you go - free your email address  
>> from your Internet provider. http://uk.docs.yahoo.com/nowyoucan.html
>>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Re: join

Damien Pollet
On 9/15/06, Todd Blanchard <[hidden email]> wrote:
> I'll just mention that mine are modeled on the NextStep routines
>
> NSString>>componentsSeparatedByString:
> NSArray>>componentsJoinedByString:

Are you using an Objective-C bridge here ?

--
 Damien Pollet
 type less, do more

Reply | Threaded
Open this post in threaded view
|

Re: join

Yanni Chiu
In reply to this post by stephane ducasse-2
stephane ducasse wrote:
> Oscar and Damien did an implementation of join and split and I would  
> really like to ease
> perl people and include such protocols in the next release (with tests)
> Now if would be nice to have a discussion on the implementations

I've also had a brush with Perl, so was looking for join/split too.
Here's what I have. Notice that split: expects a charater argument.
IIRC, the reason I did that was to make it easier to implement the
equivalent method on VAST. Also, the joinWith: doesn't use
nextPutAll:separatedBy: so I could easily implement an equivalent
method in VAST and VW.

SequenceableCollection joinWith: separator
        "Answer a string with elements converted to strings and separated by
separator."

        | ws |
        ws := WriteStream on: (String new: 100).
        self withIndexDo: [:each :i |
                ws nextPutAll: each asString.
                i < self size ifTrue: [ ws nextPutAll: separator ].
        ].
        ^ws contents

String>>split: ch
        | pieces i prev |
        pieces := OrderedCollection new.
        i := 0.
        [(i := self indexOf: ch startingAt: (prev := i + 1)) == 0] whileFalse:
                        [prev < i ifTrue: [pieces add: (self copyFrom: prev to: i - 1)].
                        prev == i ifTrue: [pieces add: String new]].
        prev <= self size
                ifTrue: [pieces add: (self copyFrom: prev to: self size)].
        (self isEmpty not and: [self last = ch]) ifTrue: [pieces add: String new].
        ^pieces


Reply | Threaded
Open this post in threaded view
|

Re: join

tblanchard
In reply to this post by Damien Pollet
No, I just reproduced their behavior in Squeak.

On Sep 15, 2006, at 9:29 AM, Damien Pollet wrote:

> On 9/15/06, Todd Blanchard <[hidden email]> wrote:
>> I'll just mention that mine are modeled on the NextStep routines
>>
>> NSString>>componentsSeparatedByString:
>> NSArray>>componentsJoinedByString:
>
> Are you using an Objective-C bridge here ?
>
> --
> Damien Pollet
> type less, do more
>


Reply | Threaded
Open this post in threaded view
|

Re: join

Oscar Nierstrasz
In reply to this post by stephane ducasse-2

Hi Folks,

Let me summarize my thoughts on the topic of split and join.

General:
- As far as I can tell, neither split: nor join: can be easily  
simulated by existing methods

On split:
- split: is fairly specific to strings, though it could be  
generalized to other kinds of Sequenceables
- split: should take a String, not a Character, as its argument (as  
in Ruby & friends)
- generally speaking, the argument to split: should be a Regex, so it  
makes sense to make String>>split: an extension to String from the  
regex package  (i.e., VB-Regex)
- string-matching is a well-known problem, so we should avoid ad hoc  
solutions.  See for example
        http://doi.acm.org/10.1145/360825.360855
For this reason I think that split: should depend on VB-Regex, unless  
someone want's to implement one of the modern algoirthms

I propose that: String>>split: ^ regexString asRegex split: self
As follows

Regex>>split: aString
        | result lastPosition |
        result := OrderedCollection new.
        stream := aString readStream.
        lastPosition := stream position.
        [ self searchStream: stream ] whileTrue:
                [ result add: (aString copyFrom: lastPosition+1 to: (self  
subBeginning: 1)).
                self assert: lastPosition < stream position description: 'Regex  
cannot match null string'.
                lastPosition := stream position ].
        result add: (aString copyFrom: lastPosition+1 to: aString size).
        ^ result

NB:
- Assertion is needed to avoid infinite loops in case of null Regex.

On join:
- join: is the conceptual inverse of split: (see the tests in http://
squeaksource.com/RubyShards/)
- join: obviously works for Sequenceables as well as Strings

I propose adding the following method to either  
SequenceableCollection or OrderedCollection [the tradeoff is not  
clear to me].

join: anOrderedCollection
        "Implicit precondition: my elements are all OrderedCollections"
        | result index |
        result := (self at: 1) writeStream.
        result nextPutAll: (self at: 1).
        index := 2.
        [index <= self size] whileTrue: [
                result nextPutAll: anOrderedCollection.
                result nextPutAll: (self at: index).
                index := index + 1.
                ].
        ^ result contents

This will clearly work not only for Strings but for other kinds of  
collections too.

SplitJoinTest>>setUp
        eg := 'Now is the time for all good men to come to the aid of the  
party'.

SplitJoinTest>>testJoin
        self assert: ((eg split: 'the') join: 'the') = eg.
        self assert: ({ {1. 2}. {4. 5} } asOrderedCollection join: {3}) =  
{1. 2. 3. 4. 5}.

Is anyone convinced?

Oscar

On Sep 15, 2006, at 17:40, stephane ducasse wrote:

> hi guys
>
> could you sit down and propose a cool set of names and  
> implementation and we include it in 3.10
>
> http://bugs.impara.de/view.php?id=4874
>


123