-->

how to stream a collection backwards without copie

2019-04-29 08:11发布

问题:

I would like to know how to stream a collection backwards without copies in Pharo/Squeak.

For example, to stream #(1 2 3) so stream next returns 3, then 2, then 1. I know I could just use collection reversed readStream, but reversed copies.

回答1:

You could use a Generator:

| coll stream |
coll := #(1 2 3).
stream := Generator on: [:g | coll reverseDo: [:ea | g yield: ea]].
stream next

Generators let you wrap a streaming interface around any piece of code, basically.



回答2:

Create the RevertingCollection class as a subclass of SequeanceableCollection with one instance variable collection. Now define these three methods (instance side):

on: aCollection
    collection := aCollection

size
    ^collection size

at: index
    ^collection at: self size - index + 1

Done. You can now do the following:

stream := (RevertingCollection new on: #(1 2 3)) readStream.

and you will get

stream next "3".
stream next "2".
stream next "1"

You can go a step further and implement the message

SequenceableCollection >> #reverseStream
    ^(RevertingCollection new on: self) readStream

In this way everything reduces to just

#(1 2 3) reverseStream

ADDENDUM

As discussed in the comments there are two pieces missing here which are:

1. An instance creation method (class side)

RevertingCollection class >> #on: aCollection
    ^self new on: aCollection

With this addition the method above should be rewritten to:

SequenceableCollection >> #reverseStream
    ^(RevertingCollection on: self) readStream

Note: Other smalltalkers would prefer this method to be named #withAll:.

2. The following method for copying:

RevertingCollection >> #copyFrom: start to: stop
    | n |
    n := self size.
    copy := collection copyFrom: n - stop + 1 to: n - start + 1.
    ^self class on: copy

This method is required to support #next: in the reverse read stream.



回答3:

There are three options off the top of my head:

  1. Modify your code to use #reverseDo:
  2. Use Xtreams
  3. Roll your own stream