user2466595
user2466595

Reputation:

extended slicing with string in python

>>>"helloworld"[::1]
'helloworld'

>>>"helloworld"[::-1]
'dlrowolleh'

according to the syntax str[start:end:step]. the start is by default 0 in both the cases. in first case the string is printed from index value 0. but in second case the string is printed from index value -1.

and my question is why is string printed from -1 in the later case and why it is so ?

Upvotes: 4

Views: 2691

Answers (7)

avasal
avasal

Reputation: 14872

Visualize this

The best way to remember how slices work is to think of the indices as pointing between characters, with the left edge of the first character numbered 0. Then the right edge of the last character of a string of n characters has index n, for example:

 +---+---+---+---+---+ 
 | H | e | l | l | o |
 +---+---+---+---+---+ 
 0   1   2   3   4   5 
-5  -4  -3  -2  -1

Indices may be negative numbers, to start counting from the right. But Note that -0 is really the same as 0, so it does not count from the right!

In [105]: "helloworld"[-0] 
Out[105]: 'h'

In [106]: "helloworld"[0]
Out[106]: 'h'

i.e. why reverse indexing starts from -1

In [107]: "helloworld"[-1] 
Out[107]: 'd'

for getting the second last index of string i.e. [-2] i.e. The last-but-one character negative stepping is required, the step is added to get to the next index

In [108]: "helloworld"[-1 + -1]
Out[108]: 'l'

Upvotes: 1

Marcelo Cantos
Marcelo Cantos

Reputation: 186118

Extended slice components all default to None (as opposed to 0 and sys.maxint for simple slicing):

>>> class A:
...   def __getitem__(self, s):
...     return s
... 
>>> A()[::-1]
slice(None, None, -1)
>>> A()[:]
slice(0, 9223372036854775807, None)

There is thus no automatic presumption that slicing should start at zero by default.

Upvotes: 2

Lauritz V. Thaulow
Lauritz V. Thaulow

Reputation: 51015

It makes no sense if start is not an implicit -1 when the string is reversed. If you try using explicit indices you will see that the start index must be to the right of the end index when using -1 as step:

>>> "helloworld"[0:-1:-1]
''
>>> "helloworld"[-1:0:-1]
'dlrowolle'

Just as when slicing the normal way, the range is including the start point and not including the end point, so h at index 0 is not part of the range. It is (AFAIK) a limitation of the slicing notation that it's not possible to do an explicit reverse of the whole string, because this does not work:

>>> "helloworld"[-1:-1:-1]
''

So a slice-and-reverse function would have to have a special case for this:

def slice_and_reverse(s, a, b):
    "Return a slice of s from a to but not including b, reversed."
    if a == 0:
        return s[b - 1::-1]
    else:
        return s[b - 1:a - 1:-1]

Upvotes: 0

BrenBarn
BrenBarn

Reputation: 251598

According to the documentation (emphasis added):

The slice of s from i to j with step k is defined as the sequence of items with index x = i + n*k such that 0 <= n < (j-i)/k. In other words, the indices are i, i+k, i+2*k, i+3*k and so on, stopping when j is reached (but never including j). If i or j is greater than len(s), use len(s). If i or j are omitted or None, they become “end” values (which end depends on the sign of k). Note, k cannot be zero. If k is None, it is treated like 1.

This means that if the slice stride is positive, an ommited slice start is the start of the sequence and an omitted slice end is the end of the sequence. If the slice stride is negative, it is the opposite. You can see this if you fill in one of the two values:

>>> '0123456'[:3]
'012'
>>> '0123456'[:3:-1]
'654'
>>> '0123456'[3:]
'3456'
>>> '0123456'[3::-1]
'3210'

One way to think of this is to visualize the sequence as a loop, where the start and end are the same point. When you omit one end of the slice, you are just specifying to use this "both-ends-point" as an endpoint, but not which direction to go from there. It is the stride sign that tells you which way to go, and this determines whether you are treating the "both-ends-point" as the beginning or the end of the sequence.

Upvotes: 8

omerkirk
omerkirk

Reputation: 2527

In python the string indices are like below.

"H e l l o"
0 1 2 3 4
-4 -3 -2 -1 0

The index that will be used depends on the direction of the slice you are taking. Because the step you gave is in the opposite direction it uses the index below. However this is not made clear in the documentation.

EDIT:

I actually rechecked and interestingly

str[::-1]
str[0::-1]
str[-1::-1]

all returns the same value. So what I said in my original post seems to be wrong. It looks more like a bug or a special case handling in the language.

Upvotes: 0

oz123
oz123

Reputation: 28888

What you are seeing is called striding:

>>> 'helloworld'[::1]

returns all the elements while

>>> 'helloworld'[::2]
'hlool'

returns every 2nd element. So, now try:

>>> 'helloworld'[::-2]
'drwle'

This returns every 2 element from the end. So, naturally, all elements from the end, is the reversed string:

>>> 'helloworld'[::-1]
'dlrowolleh'

Upvotes: 0

Rudolf M&#252;hlbauer
Rudolf M&#252;hlbauer

Reputation: 2531

with step = 1, you will get the original string, unsurprisingly.

with step = -1, python probably implements a special case: reverse the order.

after all, the slice [start:end], as [:] returns the full slice, which is the intended behaviour. so see it as a two-phased operation: get the slice (full copy in your case), the apply the stepping (reverse in your case).

Upvotes: 0

Related Questions