Possible improvement to slice opperations.

Ron Adam rrr at ronadam.com
Tue Sep 6 12:31:33 CEST 2005


Steve Holden wrote:
> Ron Adam wrote:
> 
>> Steve Holden wrote:

>>
>> What misconception do you think I have?
>>
> This was not an ad hominem attack but a commentary on many attempts to 
> "improve" the language.

Ok, No problem.  ;-)


>> No one has yet explained the reasoning (vs the mechanics) of the 
>> returned value of the following.
>>
>>     L = range(10)
>>     L[3::-1]
>>
>> So far every attempt to explain it has either quoted the documents 
>> which don't address that particular case, or assumed I'm 
>> misunderstanding something, or implied it isn't neccisary to do.
>>
>> It's quite easy to get me to change my mind on something, just show me 
>> a convincing explanation and I will. :)
>>
>  >>> L[3::-1]
> [3, 2, 1, 0]
>  >>> L[3::1]
> [3, 4, 5, 6, 7, 8, 9]
>  >>>
 >
> I don;t see the problem here. The start specifies which element is the 
> first in the slice, the stop is the default (end of the sequence) and 
> the stride is "successive elements to the left" when it's -1 and 
> "successive elements to the right" when it's 1.

This is how it works.  But determining the correct index's to use in 
some cases can be tricky.


> Or perhaps you can tell me what I've missed?

Ok, lets see...  This shows the problem with using the gap indexing model.

L = range(10)

[ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9  ]   # elements
0   1   2   3   4   5   6   7   8   9   10   # index's

L[3::1]  -> [3, 4, 5, 6, 7, 8, 9]  3rd index to end...  ok
L[3:6:1] -> [3, 4, 5]  3rd index to 6th index... ok

L[3::-1] -> [3, 2, 1, 0]  4th index to beginning... umm
L[6:3:-1] -> [6, 5, 4]  7th index to 4th index... ?

So negative strides use a different index position?

  [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9  ]   # elements
-1   0   1   2   3   4   5   6   7   8   9    # index's

L[3::-1]  -> [3, 2, 1, 0]   3rd index to beginning... ok
L[6:3:-1] -> [6, 5, 4]   6th index to 3rd index... ok

To reach the '0' we have to check the index...

if i <= -1:
    r = L[i+3::-1]
else:
    r = L[i+3:i:-1]


Using negative index's ...

  [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9  ]   # elements
-10  -9  -8  -7  -6  -5  -4  -3  -2  -1   0   # index's

L[-3::1] -> [7, 8, 9]  ok
L[-6:-3:1] -> [4, 5, 6]  ok

L[-3::-1] ->  [7, 6, 5, 4, 3, 2, 1, 0]  -2nd to -10th ?
L[-3:-6:-1] -> [7, 6, 5]  -2nd index to -5th.. ?


So we have to shift all the index's to the right again.

  [ 0  , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]   # elements
-11 -10  -9  -8  -7  -6  -5  -4  -3  -2  -1    # index's

L[-3::-1] ->  [7, 6, 5, 4, 3, 2, 1, 0]  -3rd to -11th
L[-3:-6:-1] -> [7, 6, 5]  -3rd index to -6th.

I feel it would be nicer if the index's didn't shift for negative strides.

Maybe gap addressing isn't really the best way to explain slicing?

Most of this function has to do with filling in the defaults, but it 
seems to work.  I'm sure theres a better way to determine the defaults 
than this rather awkward if-else tree.

def slc(L, start, stop=None, step=1):
     if stop == None:
         if start == None:
             if step >= 0:
                 start = 0
                 stop = len(L)
             else:
                 start = len(L)-1
                 stop = -1
         elif start >=0:
             if step>0:
                 stop = len(L)
             else:
                 stop = -1
         else:
             if step>0:
                 stop = 0
             else:
                 stop = -(len(L)+1)
     if start == None:
         if stop >= 0:
             if step>0:
                 start = 0
             else:
                 start = len(L)-1
         else:
             if step>0:
                 start = -1
             else:
                 start = 0
     new = []
     for i in range(start,stop,step):
         new.append(L[i])
     return new

This is more precise, but not neccisarily any easier to understand 
without mentally tracing the conditions.  But it's clear now why slices 
behave the way they do.


Having to reverse the order of the index's along with using -steps is a 
bit bothersome.  It might be easier if it were of the form...

      L[left:right:step]

Then positive and negative index's could be easily be mixed, and the 
slice is always the space between. Step determines the output order and 
stride.

Thats easy enough to explain even for beginners.  But as Patrick pointed 
out it's not consistent with range.

This alternate "suggestion" gets the slice first then reverses it. It 
has the advantage that the above alternate indexing adjustments go away 
also.

And.

    L[3:6:1] = L[3:6:-1]  reverses a sub sequence.


This disadvantages are: it's different, it's not compatible with current 
range.  It probably breaks more backward compatibility than I suspect.


> My point was that you can make those changes in your own code, leaving 
> others to accept the situation as it is.

It's only a suggestion and an interesting idea I thought I would share 
and see if anyone would like to discuss. I did title this as a 'possible 
improvement', and not as proposed improvement.


> Right, I wasn't trying to suggest that you didn't know what you were 
> talking about - or even that you didn't understand general relativity 
> (on which my grasp could be said to be tenuous) - merely that some 
> things are inherently difficult, and no matter how you twist the 
> implementations about, the difficulties will remain.

But shouldn't we try to make things easier when possible?

Cheers,
Ron


> regards
>  Steve



More information about the Python-list mailing list