473,839 Members | 1,526 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Possible improvement to slice opperations.


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.pytho n, 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,sto p,step)

def __getitem__(sel f, 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.s top]
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__(sel f, i, v):
#Not emplimented yet.

def __repr__(self): return 'nxlist(%r)'%se lf.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(testd ata):
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]
"""

Sep 4 '05
40 2628
Patrick Maupin wrote:
I previously wrote (in response to a query from Ron Adam):

In any case, you asked for a rationale. I'll give you mine:

>L = range(10)
>L[3:len(L):-1] == [L[i] for i in range(3,len(L),-1)]
True


After eating supper, I just realized that I could probably make my
point a bit clearer with a slightly longer example:

L = range(10)
for stride in [-3, -2, -1, 1, 2, 3]:


... for start in range(len(L)):
... for end in range(len(L)):
... P = L[start:end:strid e]
... #Q = [L[i] for i in range(start, end, stride)]


Q = [L[i] for i in range(start, end)][::stride]
... assert P == Q

With the changed line above it will pass with the example nxlist type.

The result is different because the method is different. So in order
for this test to not give an assert, the same order needs to be used.

This should never fail with an assertion error. You will note that it
shows that, for non-negative start and end values, slicing behavior is
_exactly_ like extended range behavior.
Yes, and it passes for negative start and end values as well.

I cannot imagine that the
behavior of range() could be made any more intuitive than it already
is.
If range were also changed.. (I'm not suggesting it should be)
range(0,10,-1), would count down from 10 to zero. The sign of the step
would determine which side to iterate from.

I think they are both fairly equivalent as far as intuitiveness. But I
think I agree, changing both range and slice is probably out of the
question.

I personally feel that your proposed change makes slice() less
intuitive on its own, but even if I did not feel that way, your way
would have to be SIGNIFICANTLY better than the current way to make it
worthwhile to make slice() behavior differ from that of range().
Well I did post it as a "possible" improvement, meaning I wasn't sure.
And did ask for opinions. This was the type of reply I was looking for.
Thanks for replying, and for taking a serious look. :-)

In my initial skimming of your post, I originally thought you were
referring to negative start and end values. Negative start and end
values will sometimes cause issues, but the utility of their current
implementation far outweighs the few corner cases which (as I mentioned
in an earlier post) sometimes need some special case logic to deal
with.
I was referring to both, it seemed to me that my suggestion had enough
good things in it that it would be worth asking others if it was
feasible, and also if it were desirable. In any case, it's an
interesting topic and looks like it could have been a valid alternative
if it were done this way from the start. Probably isn't good enough to
change now.

Thanks again, this pretty much explains why slices opperate the way they
do. And it explains why the edge case's happen as well I think.

Cheers,
Ron
Regards,
Pat

Sep 6 '05 #31
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
misunderstandin g 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,sto p,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

Sep 6 '05 #32

Ron Adam wrote:
This should never fail with an assertion error. You will note that it
shows that, for non-negative start and end values, slicing behavior is
_exactly_ like extended range behavior.
Yes, and it passes for negative start and end values as well.
Umm, no:

..>> for stride in [-3, -2, -1, 1, 2, 3]:
.... for start in range(-1,len(L)):
.... for end in range(-1,len(L)):
.... P = L[start:end:strid e]
.... Q = [L[i] for i in range(start, end, stride)]
.... assert P==Q, [start, end, stride, P, Q]
....
Traceback (most recent call last):
File "<stdin>", line 6, in ?
AssertionError: [-1, 0, -3, [9, 6, 3], []]
Thanks again, this pretty much explains why slices opperate the
way they do. And it explains why the edge case's happen as well I think.


You're welcome.

Regards,
Pat

Sep 6 '05 #33
Ron Adam wrote:
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


Ok, I see what you mean. The "view slices as indices standing
between the items in the sequence" model actually breaks down
with negative strides.

Then you need to view it more in the mathematical way of
half-open (or half-closed if you prefer) intervals.

[a,b) = { x | a <= x < b }

See http://en.wikipedia.org/wiki/Half-closed_interval

I still think the current sematics are the least surprising
though. For instance, if we want to implement a ring class
looking something like the one below, the logical way to do
that would allow it to be used as if it was a list.

Actually, such a ring class (extented to handle extended slices
correctly) would (I think) solve the tricky cases with things
such as l[0:-0] or l[9:-1:-1].

The complete implementation is left as an exercise to the
reader, although there's probably something like it in the
Python cookbook already.

class Ring(list):
def __init__(self, size):
self.size = size
def __setitem__(sel f, i,v):
return list.__setitem_ _(self, i%self.size, v)
def __getitem__(sel f, i):
return list.__getitem_ _(self, i%self.size)
def __setslice__(se lf, i, j, v):
return list.__setslice __(self, i%self.size, j%self.size,v)
def __getslice__(se lf, i, j):
return list.__getslice __(self, i%self.size, j%self.size)
Sep 6 '05 #34
Patrick Maupin wrote:
Ron Adam wrote:

This should never fail with an assertion error. You will note that it
shows that, for non-negative start and end values, slicing behavior is
_exactly_ like extended range behavior.
Yes, and it passes for negative start and end values as well.

Umm, no:

.>> for stride in [-3, -2, -1, 1, 2, 3]:
... for start in range(-1,len(L)):
... for end in range(-1,len(L)):
... P = L[start:end:strid e]
... Q = [L[i] for i in range(start, end, stride)]
... assert P==Q, [start, end, stride, P, Q]
...
Traceback (most recent call last):
File "<stdin>", line 6, in ?
AssertionError: [-1, 0, -3, [9, 6, 3], []]


Ah, Yes... I it was way too late last night and I mistakenly changed the
values of L... which was meaningless.

Range lines in the for statements, need to read..

range(-len(l),0)

But then it doesn't include all the values of L.

Thanks again, this pretty much explains why slices opperate the
way they do. And it explains why the edge case's happen as well I think.

You're welcome.

Regards,
Pat

Sep 6 '05 #35
Magnus Lycka wrote:
Ron Adam wrote:
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

Ok, I see what you mean. The "view slices as indices standing
between the items in the sequence" model actually breaks down
with negative strides.


Yes, that and the edge case's is why I this topic keeps coming up. Then
there's the 'None' default values that depend on both the stride sign,
and the index signs. These are all features in some context, and can be
annoyances in others. As long as you stick with positive stride values,
it's not much of a problem though, so an alternate solution will have to
be really good.

Then you need to view it more in the mathematical way of
half-open (or half-closed if you prefer) intervals.

[a,b) = { x | a <= x < b }

See http://en.wikipedia.org/wiki/Half-closed_interval
Interesting... Maybe just a different syntax that designates the stop
as being inclusive would work?

[a,b] = { x | a <= x <= b }

L[a;<b] a to b-1, same as L[a:b]
L[a;b] a to b
L[a>;b] a+1 to b
L[a>;<b] a+1 to b-1

L == L[;<i] + L[i;] == L[;i] + L[i>;]

I still think the current sematics are the least surprising
though. For instance, if we want to implement a ring class
looking something like the one below, the logical way to do
that would allow it to be used as if it was a list.

Actually, such a ring class (extented to handle extended slices
correctly) would (I think) solve the tricky cases with things
such as l[0:-0] or l[9:-1:-1].

The complete implementation is left as an exercise to the
reader, although there's probably something like it in the
Python cookbook already.

class Ring(list):
def __init__(self, size):
self.size = size
def __setitem__(sel f, i,v):
return list.__setitem_ _(self, i%self.size, v)
def __getitem__(sel f, i):
return list.__getitem_ _(self, i%self.size)
def __setslice__(se lf, i, j, v):
return list.__setslice __(self, i%self.size, j%self.size,v)
def __getslice__(se lf, i, j):
return list.__getslice __(self, i%self.size, j%self.size)


This is nice. I might even find a use for it. ;-)

Cheers,
Ron


Sep 6 '05 #36
On Tue, 06 Sep 2005 10:31:33 GMT, Ron Adam <rr*@ronadam.co m> wrote:
Steve Holden wrote: [...]
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?

Sure ;-)

It occurs to me that maybe this discussion of slicing has a parallel
in mathematical intervals, and we might usefully check if it makes sense there.

IOW, let's compare [a, b] vs [a, b) vs (a, b] vs (a,b)

ISTM the python range model corresponds to [a, b) in terms of integers. The step thing
modifies that, but leave that aside to concetrate on the main issue.

For math, I think the notation requires a<=b, but for programming, python has a convention
for specifying related intervals and a subsetting function, with similar notation adding step.

Leaving aside abs(step)!=1 which specifies subsetting, we could say that

[a:b:1]
is
[a, b)
and
[a:b,-1]
is
(a, b]

but the latter returned in reverse order.

If we factor out the issues of reversing and subsetting, we just have
the indication of which kind of interval: half-open to the right or left.

That we could do by
[a:b] => [a, b)
and
.[a:b] => (a, b]

Then the question is, do we need sugar for reversed(x.[a:b])
or list(reversed(x .[a:b])) for the right hand side of a statement,
and do we want to to use both kinds of intervals in slice assignment?
(maybe and yes ;-)

The reason for yes is that it solves the which-gap problem in assigning to [a:a]
if you define [a, a) as an empty interval to the left of a and (a, a] as an empty
interval to the right of a, sort of like +0 and -0 in half-open intervals ;-)
Replacing the empty interval does the insertion on the side you want ;-)

I am choosing the convention to stay compatible with python's current behaviour,
even though I'm not sure what the math world says about a<x<=a vs a<=x<a as
different-in-some-sense intervals. I guess the intervals as point sets are the same,
but the interval definitions are different...

Other than the a:a distinction, in terms of integers and UIAM
.[a:b]
is just sugar for
[a+1:b+1]
but the sugar is nice, and the slice assignment to either side is nicer.

I'll deal with the subsetting another time ...

Regards,
Bengt Richter
Sep 7 '05 #37
On Tue, 06 Sep 2005 18:34:13 +0200, Magnus Lycka <ly***@carmen.s e> wrote:
[...]

Then you need to view it more in the mathematical way of
half-open (or half-closed if you prefer) intervals.

[a,b) = { x | a <= x < b }

Funny, I just posted with the same thought (and some additional considerations)
I hadn't read yours yet, or I would have mentioned it ;-)

Regards,
Bengt Richter
Sep 7 '05 #38
Bengt Richter wrote:
Then the question is, do we need sugar for reversed(x.[a:b])
or list(reversed(x .[a:b])) for the right hand side of a statement,
and do we want to to use both kinds of intervals in slice assignment?
(maybe and yes ;-)
Yes, I think this is the better way to do it, as this address's the
underlying causes instead of treating the symptoms.

The reason for yes is that it solves the which-gap problem in assigning to [a:a]
if you define [a, a) as an empty interval to the left of a and (a, a] as an empty
interval to the right of a, sort of like +0 and -0 in half-open intervals ;-)
Replacing the empty interval does the insertion on the side you want ;-)

I am choosing the convention to stay compatible with python's current behaviour,
even though I'm not sure what the math world says about a<x<=a vs a<=x<a as
different-in-some-sense intervals. I guess the intervals as point sets are the same,
but the interval definitions are different...
Not sure either. I think intervals is an important concept and enabling
python to work with them would be good if it could be done in a simple
and consistent way. This extends a lot further than just slice
operations because of the relationship between ...

for x in range() -> slice(range)
So defining an interval object that can be used as an iterator in a for
loop might be the beginning, and then finally slice with an alternate
syntax to an abbreviated form. So then you would have the relationship
of...

for x in interval() -> slice(interval)

Other than the a:a distinction, in terms of integers and UIAM
.[a:b]
is just sugar for
[a+1:b+1]
but the sugar is nice, and the slice assignment to either side is nicer.
Wouldn't that be [a:b+1] ?

As sugar the index's are translated at compile time, it may run into the
current edge case indexing problems. So it will most likely need to be
an actual interval object, with an alternative syntax to use it.
I'll deal with the subsetting another time ...
No hurry, this isn't a hack it out because "the boss wants it on his
desk Monday" situation. ;-)
Regards,
Bengt Richter


Cheers,
Ron

Sep 7 '05 #39
Ron Adam <rr*@ronadam.co m> writes:
Magnus Lycka wrote:
Ron Adam wrote: [...]
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.

I think you are looking at this from the wrong perspective.
Whatever sign c has:
For s[a:b:c], a is the index for the first item to include,
b is the item after the last to include (just like .end() in
C++ iterators for instance), and c describes the step size.


Yes, and that is how it "should" work. But....

With current slicing and a negative step...

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

r[-3:] -> [7, 8, 9] # as expected
r[-3::-1] -> [7, 6, 5, 4, 3, 2, 1, 0] # surprise

The seven is include in both cases, so it's not a true inverse
selection either.


Did you read what Magnus said: "a is the index for the first item to
include"? How could r[-3::x] for any x not include the 7?

Cheers,
mwh

--
Windows 2000: Smaller cow. Just as much crap.
-- Jim's pedigree of operating systems, asr
Sep 9 '05 #40

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

15
2498
by: Roberto A. F. De Almeida | last post by:
I found that when using negative indices, the slice object passed to __getitem__ depends on the number of slices. An example to clarify: class a: def __getitem__(self, index): return index >>> b = a() >>> print b Traceback (most recent call last):
4
2936
by: F. Da Costa | last post by:
Hi, I was wondering whether someone could enlighten me as to the reason why the slice does not work in IE when the arr is passed in properly. Checked the values in the srcArr and they are correct so no problems there. Gecko works as expected. Prior to entering the function I can slice the array being entered so I wouldn't expect an "Unexpected call to method or property access" (in IE 6). I guess its something silly but as of yet i'm...
108
6485
by: Bryan Olson | last post by:
The Python slice type has one method 'indices', and reportedly: This method takes a single integer argument /length/ and computes information about the extended slice that the slice object would describe if applied to a sequence of length items. It returns a tuple of three integers; respectively these are the /start/ and /stop/ indices and the /step/ or stride length of the slice. Missing or out-of-bounds indices are handled in a manner...
23
2348
by: Antoon Pardon | last post by:
Now slices are objects in python, I was wondering if slice notation will be usable outside subscribtion in the future. Will it ever be possible to write things like: a = 4:9 for key, value in tree.items('alfa.': 'beta.'): -- Antoon Pardon
2
7258
by: smichr | last post by:
It seems to me that the indices() method for slices is could be improved. Right now it gives back concrete indices for a range of length n. That is, it does not return any None values. Using an example from clpy about this the indices for a 'None, None, -2' slice for a range of length 10 are given as '9, -1, -2'. The problem is that these concrete values cannot be fed back into a slice so that a slice will extract the same elements that...
3
2993
by: Bas | last post by:
Hi, stupid question, but would it be possible to somehow merge xrange (which is supposed to replace range in py3k) and slice? Both have very similar start, stop and step arguments and both are lightweight objects to indicate a range. But you can't do a and 'for i in slice(10,20)'. The only difference is see is some behavior with infinities (e.g. object gives a slice(3,maxint) inside _getitem_ , but I think this should not be a large...
0
9855
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
1
10647
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
10292
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
9426
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
5682
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5866
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
4482
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
4064
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
3132
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.