Xtreams question - OC of chars to String

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

Xtreams question - OC of chars to String

Chris Cunnington
I have a question about converting an OrderedCollection full of chars
into a string. [1]

I would have thought there was a method like #asString that could be
sent to an OrderedCollection to produce a string. I find myself having
to do the process in three steps: 1) #reading the OC; 2) creating an
empty string; and then, 3) iterating over every char to put it into the
String.

I think I'm missing a simpler way. Especially with Xtreams. Shouldn't I
just use a filter, change the #contentSpecies, or something?

Chris


[1]

startTag: data
     <action: 'element'>
     |tagdata str |
     tagdata := data second first reading.
     str := (String new: 20) writing.
     tagdata do: [:each| str put: each].
     ^'html ' , (data first second first asString) , $: , $' , (str
close; terminal) , $'


Reply | Threaded
Open this post in threaded view
|

Re: Xtreams question - OC of chars to String

Bob Arning-2

String withAll: yourCollection

as in...

String withAll: (#($a $b $c) asOrderedCollection)

On 12/29/12 12:30 PM, Chris Cunnington wrote:
I have a question about converting an OrderedCollection full of chars into a string. [1]

I would have thought there was a method like #asString that could be sent to an OrderedCollection to produce a string. I find myself having to do the process in three steps: 1) #reading the OC; 2) creating an empty string; and then, 3) iterating over every char to put it into the String.

I think I'm missing a simpler way. Especially with Xtreams. Shouldn't I just use a filter, change the #contentSpecies, or something?

Chris


[1]

startTag: data
    <action: 'element'>
    |tagdata str |
    tagdata := data second first reading.
    str := (String new: 20) writing.
    tagdata do: [:each| str put: each].
    ^'html ' , (data first second first asString) , $: , $' , (str close; terminal) , $'






Reply | Threaded
Open this post in threaded view
|

Re: Xtreams question - OC of chars to String

douglas mcpherson
In reply to this post by Chris Cunnington
The following works:

String withAll: #($a $b $c)

But I'm not sure I'm answering your question. 


On Dec 29, 2012, at 09:30 , Chris Cunnington wrote:

I have a question about converting an OrderedCollection full of chars into a string. [1]

I would have thought there was a method like #asString that could be sent to an OrderedCollection to produce a string. I find myself having to do the process in three steps: 1) #reading the OC; 2) creating an empty string; and then, 3) iterating over every char to put it into the String.

I think I'm missing a simpler way. Especially with Xtreams. Shouldn't I just use a filter, change the #contentSpecies, or something?

Chris


[1]

startTag: data
   <action: 'element'>
   |tagdata str |
   tagdata := data second first reading.
   str := (String new: 20) writing.
   tagdata do: [:each| str put: each].
   ^'html ' , (data first second first asString) , $: , $' , (str close; terminal) , $'





Reply | Threaded
Open this post in threaded view
|

Re: Xtreams question - OC of chars to String

Chris Cunnington
On 2012-12-29 12:53 PM, Douglas McPherson wrote:
The following works:

String withAll: #($a $b $c)

But I'm not sure I'm answering your question. 


Thank you Bob and Douglas. That's a nice simple solution that I was unfamiliar with. Perfect.

Happy New Year,
Chris


Reply | Threaded
Open this post in threaded view
|

Re: Xtreams question - OC of chars to String

Levente Uzonyi-2
In reply to this post by Chris Cunnington
On Sat, 29 Dec 2012, Chris Cunnington wrote:

> I have a question about converting an OrderedCollection full of chars into a
> string. [1]

| oc |
oc := #($a $b $c) asOrderedCollection.
oc as: String.

>
> I would have thought there was a method like #asString that could be sent to
> an OrderedCollection to produce a string. I find myself having to do the
> process in three steps: 1) #reading the OC; 2) creating an empty string; and
> then, 3) iterating over every char to put it into the String.

Since the size of Strings (or an instance of a variable class in general)
can't be changed, therefore creating an empty String and concatenating to
it one character at a time is a bad pattern in Smalltalk. Your algorithm
will need O(n^2) time to finish (where n is the number of characters), and
you'll also waste O(n^2) space, which will make your code even slower,
since the intermediate collections will have to be garbage collected.


Levente

>
> I think I'm missing a simpler way. Especially with Xtreams. Shouldn't I just
> use a filter, change the #contentSpecies, or something?
>
> Chris
>
>
> [1]
>
> startTag: data
>    <action: 'element'>
>    |tagdata str |
>    tagdata := data second first reading.
>    str := (String new: 20) writing.
>    tagdata do: [:each| str put: each].
>    ^'html ' , (data first second first asString) , $: , $' , (str close;
> terminal) , $'
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Xtreams question - OC of chars to String

Chris Cunnington
On 2012-12-29 1:47 PM, Levente Uzonyi wrote:
> On Sat, 29 Dec 2012, Chris Cunnington wrote:
>
>> I have a question about converting an OrderedCollection full of chars
>> into a string. [1]
>
> | oc |
> oc := #($a $b $c) asOrderedCollection.
> oc as: String.
>
Thanks.

>>
>> I would have thought there was a method like #asString that could be
>> sent to an OrderedCollection to produce a string. I find myself
>> having to do the process in three steps: 1) #reading the OC; 2)
>> creating an empty string; and then, 3) iterating over every char to
>> put it into the String.
>
> Since the size of Strings (or an instance of a variable class in
> general) can't be changed, therefore creating an empty String and
> concatenating to it one character at a time is a bad pattern in
> Smalltalk. Your algorithm will need O(n^2) time to finish (where n is
> the number of characters), and you'll also waste O(n^2) space, which
> will make your code even slower, since the intermediate collections
> will have to be garbage collected.
>
>
> Levente
I rolled the versions forward and back to try them out. It's much slower
concatenating one character at a time. I figured there had to be a
better way, but wasn't seeing it.

Thanks,
Chris

>>
>> I think I'm missing a simpler way. Especially with Xtreams. Shouldn't
>> I just use a filter, change the #contentSpecies, or something?
>>
>> Chris
>>
>>
>> [1]
>>
>> startTag: data
>>    <action: 'element'>
>>    |tagdata str |
>>    tagdata := data second first reading.
>>    str := (String new: 20) writing.
>>    tagdata do: [:each| str put: each].
>>    ^'html ' , (data first second first asString) , $: , $' , (str
>> close; terminal) , $'
>>
>>
>>
>


Reply | Threaded
Open this post in threaded view
|

Re: Xtreams question - OC of chars to String

Frank Shearar-3
In reply to this post by Chris Cunnington
On 29 December 2012 17:30, Chris Cunnington
<[hidden email]> wrote:

> I have a question about converting an OrderedCollection full of chars into a
> string. [1]
>
> I would have thought there was a method like #asString that could be sent to
> an OrderedCollection to produce a string. I find myself having to do the
> process in three steps: 1) #reading the OC; 2) creating an empty string; and
> then, 3) iterating over every char to put it into the String.
>
> I think I'm missing a simpler way. Especially with Xtreams. Shouldn't I just
> use a filter, change the #contentSpecies, or something?

You're getting Characters, I guess, because you're reading one element
at a time [1]. There's nothing stopping you reading more than that:

('abc' reading read: 3) = 'abc'.
('abc reading rest) = 'abc'.

frank

[1] It's worth bearing in mind that Xtreams operate over streams of
arbitrary objects, not just characters.

> Chris
>
>
> [1]
>
> startTag: data
>     <action: 'element'>
>     |tagdata str |
>     tagdata := data second first reading.
>     str := (String new: 20) writing.
>     tagdata do: [:each| str put: each].
>     ^'html ' , (data first second first asString) , $: , $' , (str close;
> terminal) , $'
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Xtreams question - OC of chars to String

Chris Cunnington
On 2012-12-29 3:46 PM, Frank Shearar wrote:

> On 29 December 2012 17:30, Chris Cunnington
> <[hidden email]> wrote:
>> I have a question about converting an OrderedCollection full of chars into a
>> string. [1]
>>
>> I would have thought there was a method like #asString that could be sent to
>> an OrderedCollection to produce a string. I find myself having to do the
>> process in three steps: 1) #reading the OC; 2) creating an empty string; and
>> then, 3) iterating over every char to put it into the String.
>>
>> I think I'm missing a simpler way. Especially with Xtreams. Shouldn't I just
>> use a filter, change the #contentSpecies, or something?
> You're getting Characters, I guess, because you're reading one element
> at a time [1]. There's nothing stopping you reading more than that:
>
> ('abc' reading read: 3) = 'abc'.
> ('abc reading rest) = 'abc'.
>
> frank
>
> [1] It's worth bearing in mind that Xtreams operate over streams of
> arbitrary objects, not just characters.
I don't know. The situation is more like:

     oc := #($a $b $c).
     oc := oc asOrderedCollection.
     oc reading read: 3   an OrderedCollection($a $b $c)


The terminal is the OC. But it returns an OC and I want a string from
the chars. I've been looking at the transforms page of the Xtreams docs
and that seems more about changing the encoding. I think my problem
wasn't really about Xtreams.

Chris

>> Chris
>>
>>
>> [1]
>>
>> startTag: data
>>      <action: 'element'>
>>      |tagdata str |
>>      tagdata := data second first reading.
>>      str := (String new: 20) writing.
>>      tagdata do: [:each| str put: each].
>>      ^'html ' , (data first second first asString) , $: , $' , (str close;
>> terminal) , $'
>>
>>


Reply | Threaded
Open this post in threaded view
|

Re: Xtreams question - OC of chars to String

mkobetic
In reply to this post by Chris Cunnington
"Chris Cunnington"<[hidden email]> wrote:

> I don't know. The situation is more like:
>
>      oc := #($a $b $c).
>      oc := oc asOrderedCollection.
>      oc reading read: 3   an OrderedCollection($a $b $c)
>
>
> The terminal is the OC. But it returns an OC and I want a string from
> the chars. I've been looking at the transforms page of the Xtreams docs
> and that seems more about changing the encoding. I think my problem
> wasn't really about Xtreams.

Hm, I have to admit that collection streams should perhaps support overriding their contentsSpecies. As it is they assume it should be the same as that of their underlying collection. One might argue that terminal streams should stick to their primary purpose of accessing terminals rather than trying to support some types of conversions as well. But there already is a precedent of sorts in the external streams, so it's not entirely solid argument either.

Barring that, you could write instead of reading, which would allow you to control the type of the terminal collection.

        String new writing write: 'abcdefg' asOrderedCollection; close; terminal

The reading equivalent would be using the longer version of read where you pass in the target collection but you're then forced to handle the collection size explicitly which seems less elegant:

        oc :=  'abcdefg' asOrderedCollection.
        string := String new: oc size.
        oc reading read: oc size into: string.

It feels sort of like doing the job of the write stream above by hand. You could also use an identity transform that allows setting the contents species:

        ('abcdefg' asOrderedCollection reading collecting: [ :c | c ]) contentsSpecies: String; rest

But that again feels like more trouble than it's worth. I think that's about all that Xtreams have to offer here.

HTH,

Martin



Reply | Threaded
Open this post in threaded view
|

Re: Xtreams question - OC of chars to String

Colin Putney-3
In reply to this post by Chris Cunnington


On Sat, Dec 29, 2012 at 12:30 PM, Chris Cunnington <[hidden email]> wrote:
I think I'm missing a simpler way. Especially with Xtreams. Shouldn't I just use a filter, change the #contentSpecies, or something?

Yeah, writing into an OrderedCollection with a stream is a bit suspect to begin with. Both provide a way to grow an underlying fix-size collection as you add more elements. If you have an OrderedCollection, you can just send #add:, no need for a write stream. If you want to build a string, "String new writing" will do the job, no need for an OrderedCollection. 

Also, you can write an OC full of characters directly into a write stream on a string:

chars := 'abc' asOrderedCollection.
String new writing 
write: '123';
write: chars; 
conclusion

Colin


Reply | Threaded
Open this post in threaded view
|

Re: Xtreams question - OC of chars to String

Chris Cunnington
In reply to this post by mkobetic
On 2012-12-30 1:01 AM, [hidden email] wrote:

> "Chris Cunnington"<[hidden email]> wrote:
>> I don't know. The situation is more like:
>>
>>       oc := #($a $b $c).
>>       oc := oc asOrderedCollection.
>>       oc reading read: 3   an OrderedCollection($a $b $c)
>>
>>
>> The terminal is the OC. But it returns an OC and I want a string from
>> the chars. I've been looking at the transforms page of the Xtreams docs
>> and that seems more about changing the encoding. I think my problem
>> wasn't really about Xtreams.
> Hm, I have to admit that collection streams should perhaps support overriding their contentsSpecies. As it is they assume it should be the same as that of their underlying collection. One might argue that terminal streams should stick to their primary purpose of accessing terminals rather than trying to support some types of conversions as well. But there already is a precedent of sorts in the external streams, so it's not entirely solid argument either.
> Barring that, you could write instead of reading, which would allow you to control the type of the terminal collection.
>
> String new writing write: 'abcdefg' asOrderedCollection; close; terminal
That's pretty nifty. Perhaps I was reading when I should have been writing.

>
> The reading equivalent would be using the longer version of read where you pass in the target collection but you're then forced to handle the collection size explicitly which seems less elegant:
>
> oc :=  'abcdefg' asOrderedCollection.
> string := String new: oc size.
> oc reading read: oc size into: string.
>
> It feels sort of like doing the job of the write stream above by hand. You could also use an identity transform that allows setting the contents species:
>
> ('abcdefg' asOrderedCollection reading collecting: [ :c | c ]) contentsSpecies: String; rest
Stacks and transforms came to mind with Xtreams: sending one kind of
content into another stream while changing the elements. This was I was
trying to reach for, but you first example looks the best.

Thanks,
Chris
>
> But that again feels like more trouble than it's worth. I think that's about all that Xtreams have to offer here.
>
> HTH,
>
> Martin
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Xtreams question - OC of chars to String

Chris Cunnington
In reply to this post by Colin Putney-3
On 2012-12-30 8:52 AM, Colin Putney wrote:


On Sat, Dec 29, 2012 at 12:30 PM, Chris Cunnington <[hidden email]> wrote:
I think I'm missing a simpler way. Especially with Xtreams. Shouldn't I just use a filter, change the #contentSpecies, or something?

Yeah, writing into an OrderedCollection with a stream is a bit suspect to begin with. Both provide a way to grow an underlying fix-size collection as you add more elements. If you have an OrderedCollection, you can just send #add:, no need for a write stream. If you want to build a string, "String new writing" will do the job, no need for an OrderedCollection. 

Also, you can write an OC full of characters directly into a write stream on a string:

chars := 'abc' asOrderedCollection.
String new writing 
write: '123';
write: chars; 
conclusion

Colin
Martin also made it look easier with a write than a read. I think I was looking at it the wrong way around. The OC shouldn't be the receiver but the argument. #writing into a String instead of #reading an OC.

Thanks,
Chris