After considering several alternatives and trying out a few ideas with a 
  modified list object Bengt Richter posted, (Thank You), I think I've 
found a way to make slice operation (especially far end indexing) 
symmetrical and more consistent.

So to find out if this is indeed a possibility, it would be nice to get 
a few opinions at this point.  So blast away... or hopefully tell me 
what you like about it instead. ;-)

(Any suggestions or contributions to make it better would be appreciated.)

Cheers,
Ron Adam



"""
IMPROVED SLICING
================

Slicing is one of the best features of Python in my opinion, but
when you try to use negative index's and or negative step increments
it can be tricky and lead to unexpected results.

This topic has come up fairly often on comp.lang.python, and often 
times, the responses include:

     * Beginners should avoid negative extended slices.

     * Slices with negative step increments are for advanced
       python programmers.

     * It's not broke if you look at it in a different way.

     * You should do it a different way.

All of these and various responses similar to them are unsatisfactory in
my opinion and it's a good indicator it's not as good as it could be.
Indexing and slice operations are vary common in Python and I don't
think we should be discouraging people from learning and using them.


COMPATIBILITY
-------------
Because the following suggested changes will break current code,
it probably can not be implemented prior to Python 3000.

     + Direct indexing with both positive and negative values
       returns the same items as they do now.

     + Extended slices with all positive and or empty default
       values remain unchanged.

     - Extended slices with negative values return values that
       have less items than currently.

     - Slices with negative step values return entirely different
       results.


REVERSE ORDER STEPPING
----------------------
When negative steps are used, a slice operation
does the following.  (or the equivalent)

    1. reverse the list
    2. cut the reversed sequence using start and stop
    3. iterate forward using the absolute value of step.

* This order results in an inverse selection and I believe should be
considered a bug.

Changing the order in the following way results in a much
more predictable pattern which is both easier to understand and use.

    1. cut sequence using start and stop.
    2  reverse the order of the results.
    3. iterate forward using the absolute value of step.


CURRENT INDEXING
----------------

Given a range [a,b,c]:

   Positive indexing

   | a | b | c |
   +---+---+---+
   0   1   2   3

   Current negative indexing.

   | a | b | c |
   +---+---+---+
  -3  -2  -1  -0


When a single index is used the item to the
right of the index for both positive and
negative index's is returned.

With slices, the items between start, and
stop index's are returned.

Accessing a range at the end of a list numerically
becomes inconvenient when negative index's are used
as the '-0'th position can not be specified numerically
with negative values.


ONES BASED NEGATIVE INDEXING
----------------------------
Making negative index's Ones based, and selecting
individual item to the left of negative index's would enable
addressing the end of the list numerically.

   Ones based negative index's.

   | a | b | c |
   +---+---+---+
  -4  -3  -2  -1

Then:

    a[-1]    -> c  # item left of index, same result as now.

    a[-3:-2] -> b  # item between index's

    a[-1:-1] = [d]  # insert item at the end.



USE OF '~' IN PLACE OF NEGATIVE INDEX'S
---------------------------------------

The '~' is the binary not symbol which when used
with integers returns the two's compliment. This
works nice with indexing from the end of a list
because convieniently ~0 == -1.

This creates a numerical symmetry between positive
indexing and '~' "End of list" indexing.

    a[0]  -> first item in the list.
    a[~0] -> last item in the list.

    a[0:~0] -> whole list.

    a[1:~1] -> center, one position from both ends.

* Note: using '~' works as described here in place of single negative 
index's in current versions of Python.  It does not work as described 
here for extended slices.

"""



# TEST LIST CLASS.
"""
    A list class to Test '~' end of list indexing.

    * This class modifies the slice before returning
    a value. The final implementation may do this by
    modifying slice objects directly or the underlying
    C code of sequences.

"""

class nxlist(object):

     def __init__(self, value):
         self.value = value

     def normslc(self, slc):
         start,stop,step = slc.start, slc.stop, slc.step
         if type(start) == int and start<0:
             start = len(self.value)+start+1
         if type(stop) == int and stop<0:
             stop = len(self.value)+stop+1
         return slice(start,stop,step)

     def __getitem__(self, i):
         tp = i.__class__
         if tp == int:
             if i>=0:
                 return self.value[i]
             else:
                 return self.value[ len(self.value)+i ]
         if tp == slice:
             slc = self.normslc(i)
             value = self.value[slc.start:slc.stop]
             if type(i.step) == int and i.step<0:
                 value.reverse()
                 slc = slice(None,None,-i.step)
             else:
                 slc = slice(None,None,i.step)
             return value[slc]

     #def __setitem__(self, i, v):
         #Not emplimented yet.

     def __repr__(self): return 'nxlist(%r)'%self.value


a = nxlist(range(10))
print a

testdata = [
     ('a[0]'),
     ('a[1]'),
     ('a[~0]'),
     ('a[~1]'),
     ('a[:]'),
     ('a[:~1]'),
     ('a[~1:]'),
     ('a[::]'),
     ('a[0:~0]'),
     ('a[1:~1]'),
     ('a[~1:1]'),
     ('a[::-2]'),
     ('a[:3]'),
     ('a[3:]'),
     ('a[~3:]'),
     ('a[:~3]'),
     ('a[:3:-1]'),
     ('a[3::-1]'),
     ('a[~3::-1]'),
     ('a[:~3:-1]'),
     ('a[:3:-2]'),
     ('a[3::-2]'),
     ('a[~3::-2]'),
     ('a[:~3:-2]'),
     ]

for n, s in enumerate(testdata):
     print '%r. %s = %r' % (n,s,eval(s))


"""
nxlist([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
0. a[0] = 0
1. a[1] = 1
2. a[~0] = 9
3. a[~1] = 8
4. a[:] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
5. a[:~1] = [0, 1, 2, 3, 4, 5, 6, 7, 8]
6. a[~1:] = [9]
7. a[::] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
8. a[0:~0] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
9. a[1:~1] = [1, 2, 3, 4, 5, 6, 7, 8]
10. a[~1:1] = []
11. a[::-2] = [9, 7, 5, 3, 1]
12. a[:3] = [0, 1, 2]
13. a[3:] = [3, 4, 5, 6, 7, 8, 9]
14. a[~3:] = [7, 8, 9]
15. a[:~3] = [0, 1, 2, 3, 4, 5, 6]
16. a[:3:-1] = [2, 1, 0]
17. a[3::-1] = [9, 8, 7, 6, 5, 4, 3]
18. a[~3::-1] = [9, 8, 7]
19. a[:~3:-1] = [6, 5, 4, 3, 2, 1, 0]
20. a[:3:-2] = [2, 0]
21. a[3::-2] = [9, 7, 5, 3]
22. a[~3::-2] = [9, 7]
23. a[:~3:-2] = [6, 4, 2, 0]
"""


r = range(10)
a = nxlist(r)

print r[~0],a[~0]     # ok
print r[~3:],a[~3:]   # one off
print r[~3::-1],a[~3::-1]  # other side
print r[~3::-2],a[~3::-2]  # other side


"""
Comparisons of negative indexing and '~'
indexing with same values.

current, proposed

9 9
[6, 7, 8, 9] [7, 8, 9]
[6, 5, 4, 3, 2, 1, 0] [9, 8, 7]
[6, 4, 2, 0] [9, 7]
"""



-- 
http://mail.python.org/mailman/listinfo/python-list

Reply via email to