Testing if an index is in a slice

M

mmanns

Hi

I would like to check if an index is in a slice or not without
iterating over the slice.

Something like:
True

I would like to use the batteries if possible.
However, I looked in the docs, pypi and in Usenet without luck.

Does anyone have a solution?

Martin
 
A

ajaksu

I would like to check if an index is in a slice or not without
iterating over the slice.

Something like:


True

I think it'd be feasible for slices that can be mapped to ranges[1],
but slices are more flexible than that.

What would the answer be for:

?

This shows the issue:
sli = slice(0, -1, 1)
range(4)[sli] [0, 1, 2]
range(10)[sli]
[0, 1, 2, 3, 4, 5, 6, 7, 8]

HTH,
Daniel

[1]
http://article.gmane.org/gmane.comp.python.python-3000.devel/8732
 
A

Aaron Brady

Hi

I would like to check if an index is in a slice or not without
iterating over the slice.

Something like:


True

I would like to use the batteries if possible.
However, I looked in the docs, pypi and in Usenet without luck.

Does anyone have a solution?

Martin

Untested:

if slice.end< 0:
slice.end= len( obj )- slice.end+ 1
if slice.step< 0 and slice.start<= target< slice.end:
return True
if slice.step> 0 and slice.start>= target> slice.end:
return True
return False
 
B

Bryan Olson

ajaksu said:
I would like to check if an index is in a slice or not without
iterating over the slice.

Something like:

True

I think it'd be feasible for slices that can be mapped to ranges[1],
but slices are more flexible than that.

If we add a parameter for the length of the list to which the slice is
applied, then inslice() is well-defined.

I thought it would easy to write, but that was hours ago when I knew
less about Python slice indexing than I do now. And I thought I new a
bunch from writing a virtual slice class.

I'm leaning towards mmanns' idea that this should be built in. Handling
all the cases is remarkably tricky. Here's a verbose version, with a
little test:


def inslice(i, slc, length):
""" Would index i be part of slice slc of a list of len length?
"""

step = slc.step or 1

if step > 0:

if slc.start is None:
start = 0
elif slc.start >= 0:
start = slc.start
else:
start = max(0, length + slc.start)

if slc.stop is None:
stop = length
elif slc.stop >= 0:
stop = min(length, slc.stop)
else:
stop = length + slc.stop

return start <= i < stop and (i - start) % step == 0

else:

if slc.start is None:
start = length - 1
elif slc.start >= 0:
start = min(length - 1, slc.start)
else:
start = length + slc.start

if slc.stop is None:
stop = -1
elif slc.stop >= 0:
stop = slc.stop
else:
stop = max(-1, length + slc.stop)

return start >= i > stop and (start - i) % (-step) == 0



# test
for start in [None, 0, 1, -1, -3, 4]:
for stop in [None, 0, 1, -1, 3, -5]:
for step in [None, 1, -1, 2, -3]:
for n in [0, 1, 2, 3, 5, 11, 16]:
slc = slice(start, stop, step)
s1 = [i for i in range(-3, n + 5) if inslice(i, slc, n)]
s2 = sorted(range(n)[slc])
assert s1 == s2
 
A

ajaksu

If we add a parameter for the length of the list to which the slice is
applied, then inslice() is well-defined.
Cool!

I thought it would easy to write,

Heh, I gave up on the example I mentioned above :)
but that was hours ago when I knew
less about Python slice indexing than I do now. And I thought I new a
bunch from writing a virtual slice class.

Maybe you could write about what you learned in the docs?
I'm leaning towards mmanns' idea that this should be built in. Handling
all the cases is remarkably tricky.

Even without testing your code, I agree. I suggest that you add this
as a feature request to the tracker at http://bugs.python.org/. I hope
Raymond Hettinger likes it and adds an islice version :)
 
S

Steven D'Aprano

I'm leaning towards mmanns' idea that this should be built in.

What's the use-case for it?

Handling
all the cases is remarkably tricky. Here's a verbose version, with a
little test:

[snip code]

Here's a less verbose version which passes your test cases:

def inslice(index, slc, len):
"""Return True if index would be part of slice slc of a
sequence of length len, otherwise return False.
"""
start, stop, stride = slc.indices(len)
if stride < 0:
return (start >= index > stop) and ((start-index) % -stride == 0)
else:
return (start <= index < stop) and ((index-start) % stride == 0)


(Hint: help(slice) is your friend.)
 
B

Bryan Olson

Steven said:
Here's a less verbose version which passes your test cases:

def inslice(index, slc, len):
"""Return True if index would be part of slice slc of a
sequence of length len, otherwise return False.
"""
start, stop, stride = slc.indices(len)
if stride < 0:
return (start >= index > stop) and ((start-index) % -stride == 0)
else:
return (start <= index < stop) and ((index-start) % stride == 0)


(Hint: help(slice) is your friend.)

I should really think about abandoning my strategy of doing everything
the hard way.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top