on slices, negative indices, which are the equivalent procedures?

Jack Brandom jbrandom at example.com
Thu Aug 5 20:00:08 EDT 2021


"Michael F. Stemper" <michael.stemper at gmail.com> writes:

> On 05/08/2021 12.35, Jack Brandom wrote:
>> The FAQ at
>>    https://docs.python.org/3/faq/programming.html#what-s-a-negative-index
>> makes me think that I can always replace negative indices with
>> positive
>> ones --- even in slices, although the FAQ seems not to say anything
>> about slices.
>> With slices, it doesn't seem to always work.  For instance, I can
>> reverse a "Jack" this way:
>> 
>>>>> s = "Jack Brandom"
>>>>> s[3 : -13 : -1]
>> 'kcaJ'
>> I have no idea how to replace that -13 with a positive index.  Is it
>> possible at all?
>
> I don't think so, because the second number (in this case -13) is the
> index before which you stop.

So, can you write a procedure that implements these rules?  It seems
that I'd begin at position 3 (that's "k" which I save somewhere), then I
subtract 1 from 3, getting 2 (that's "c", which I save somewhere), then
I subtract 1 from 2, getting 1 (that's "a", ...), then I subtract 1 from
1, getting 0 (that's J, ...), so I got "kcaJ" but my counter is 0 not
-13, which was my stopping point.

So it doesn't work as I'm currently thinking --- and my attempt to write
a procedure would not work.  There must be a procedure that mimics this,
of course.  I haven't understood the rules enough yet.

> For example:
>
>>>> s
> 'Jack Brandom'
>>>> s[3:0:-1]
> 'kca'

Okay, so we begin at 3 (which is "k"), then we go towards the beginning
of the string because of step = -1.  This would work with my iteration
attempted above --- I'd subtract 1 from 3, then from 2, then from 1 and
I'd stop as soon as I reach 0, so I wouldn't collect the J, as desired.
(I could write, therefore, such procedure for this case.)

>>>> s[3:1:-1]
> 'kc'

Okay.

> However, since you want to go through item 0 in the original string,
> you don't need a number there at all:
>
>>>> s[3::-1]
> 'kcaJ'

Thanks for mentioning this.

> Or, it you want to be more explicit, you could separately grab the
> substring and then reverse it:
>
>>>> s[:4][::-1]
> 'kcaJ'

This is interesting.  It's a way to break the problem into smaller
steps.  So [::-1] always reverses the iterable.

> Does any of this help?

It does.  Thank you.  But my main objective is to imitate the rules of
slicing so that I can understand it.  In other words, I'd like to write
myself a procedure --- say mySlice --- that takes an iterable and three
integers (say beg, end, step) and be able to produce precisely

  iterable[beg : end : step]

without using this syntax.  This would give me the feeling that I really
know how it works.  (Because I simulated it.)

Ignoring the type of the iterable for now, I could begin with something
like this:

--8<---------------cut here---------------start------------->8---
def mySlice(it, beg, end, step = 1):
  ret = []
  cur = beg
  if step > 0:
    while cur < end:
      ret.append(it[cur])
      cur += 1
    return ret
  if step < 0:
    return "not sure yet"
--8<---------------cut here---------------end--------------->8---

>>> "Jack Brandom"[0:4:1]
'Jack'

>>> mySlice("Jack Brandom", 0, 4, 1)
['J', 'a', 'c', 'k']

That's the spirit.  I can say I know the behavior because I can imitate
it perfectly.  But there seems to be various combinations of positive
and negative in the indices that confuses my mind pretty easily.

I think I need to break this down into cases and understand all the
possible behaviors.  For now, I think I can say that if the step is
positive, then it goes from the first indice to the second.  (It moves
in that direction.)  If the step is negative, then it goes from the
first indice to the second but the second must be smaller than the
first.  (But I'm assuming here all indices are positive and only the
step can switch sign.)  (This thing is looking too confusing. I must be
missing some simple rule.)


More information about the Python-list mailing list