Re: obtaining the reversal of a sequence?

Steven D. Majewski (sdm7g@elvis.med.virginia.edu)
Thu, 28 Oct 1993 11:41:03 -0400

While elvis.med.virginia.edu was getting it's disks scrubbed and
cleaned, I missed the original question that started the thread
about range and reverse.

On Oct 20, 23:27, Bill Janssen wrote:
>
> I've encountered the problem where I'd like to have a sequence that is
> traversed in both directions equally frequently. It's a display list, and
> is traversed from back to front, to paint the window, and from front to
> back, to find the innermost element enclosing a point.
>
> Clearly, the ``for foo in x'' construct works well for one of the two
> cases, but what's the efficient way to traverse the list in reverse order?
> The best I can come up with is:
>
> tmp = list[:]
> tmp.reverse()
> for x in tmp:
> blah...
>
> and that's so inefficient I believe there must be some trick tucked away
> to make this easier.
>
> Bill
>
>
> -- End of excerpt from Bill Janssen <janssen@parc.xerox.com>

But playing around with pseudo-sequences ( in my prev. posts ) suggests
a trick:

class Rev:
def __init__( self, seq ):
self.forw = seq
self.back = self
def __len__( self ):
return len( self.forw )
def __getitem__( self, j ):
return self.forw[ -( j + 1 ) ]
def __repr__( self ):
return '<reverse of sequence: ' + repr(self.forw) +' >'

It works on mutable or inmutable sequences.

>>> for c in Rev( 'Hello World!' ) : sys.stdout.write( c )
... else: sys.stdout.write( '\n' )
...
!dlroW olleH
>>>

The .forw is so you can use anonymous sequences in init, and still
keep a reference the forward sequence. )
If you give it a non-anonymous mutable sequence, the reverse sequence
will track the updated values. ( but not reassignment! - another
good reason to use anonymous values in creating the sequence to avoid
confusion. Maybe it should be change to copy input sequence to break
the connection completely ? )

>>> nnn = range( 0, 3 )
>>> rnn = Rev( nnn )
>>> for n in rnn: print n
...
2
1
0
>>> for n in range( 4, 6 ): nnn.append( n ) # update nnn
...
>>> for n in rnn: print n # prints reversed updated values
...
5
4
2
1
0
>>> nnn = nnn[1:-1]
>>> nnn
[1, 2, 4]
>>> for n in rnn: print n # prints reversed values of old nnn
...
5
4
2
1
0
>>>

I'll leave it to Guido or someone else to figure out how this
compares effeciency wise with the other solutions.

ToDo's:
repr() ought to return a more natural representation, but then it
has to check for type of argument to know whether to wrap the
reversed values in "[]" or "()" or something else or nothing.

Add more methods to make rseq.back completely comparable to
rseq.forw. e.g. rseq.back.append( ) would insert a value at
the BEGINNING of rseq.forw. , etc.

Also note to Terrence Brannon and others who have complained about
strings being non-mutable: you can probably tell from these various
pseudo-sequences that it would be pretty easy to make a mutable-string
class. It isn't something I've felt as a requirement, but since it's
so easy, maybe we ought to put one in the standard library.

Right now I'm more interested in figuring out a more natural way of
expressing regular expressions and other non-regexp patterns ( like
matching parends. ) using operators on character set classes and
pattern classes instead of characters with special meanings that may
or may not have to be escaped.
i.e. something like:
Any( letters ) + Any( letters ) * 5 + Any( digits + '_$' ) * 3
( where letters and digits are imported from string, and 'Any' would be
a class constructor. )
translating into regexp: [a-zA-Z][a-zA-A]*5[0-9]*3
( where *5 means 0-5 occurances - a specification feature I've not seen
in all regexp modules. )

Any comments on the usefulness of this sort of interface to regexp, or
the desired syntax or semantics ?

- Steve Majewski