Levon
Levon

Reputation: 143112

Why does [-1:-1:-1] not work for reversing a string?

Maybe someone can explain why a particular slice operation to reverse a string doesn't work. There must be something about slices I don't understand. Basic operation: s[start:end:step]

Given

s='abcd'

to reverse this string I can do using default values

s[::-1]

or

s[-1::-1]

Those are fine, but why doesn't

s[-1:-1:-1]

work and give me the whole string reversed? It should start at with the last character in the string at (-1), and the stepsize is -1. It should run down to one before -1 i.e., index 0. Instead I get ''.

for i in xrange(3, -2, -1):
    print 's[-1:%d:-1] => ' %i,
    print s[-1:i:-1]

yields:

s[-1:3:-1] =>     # didn't expect any output
s[-1:2:-1] =>  d
s[-1:1:-1] =>  dc
s[-1:0:-1] =>  dcb
s[-1:-1:-1] =>    # shouldn't this be 'dcba'?

what am I missing here?

(I did see a lot of posting on reversing strings, but if this particular item was explained somewhere I missed it)

Upvotes: 3

Views: 776

Answers (6)

Mark Ransom
Mark Ransom

Reputation: 308402

That's kind of unfortunate, isn't it? Here's an awkward workaround.

for i in range(3, -2, -1):
    j = i if i != -1 else None
    print 's[-1:%s:-1] => ' % str(j),
    print s[-1:j:-1]

s[-1:3:-1] =>  
s[-1:2:-1] =>  d
s[-1:1:-1] =>  dc
s[-1:0:-1] =>  dcb
s[-1:None:-1] =>  dcba

Here's a variation on the same thing. I'm not sure if it's any less awkward.

for i in range(3, -1, -1) + [None]:
    print 's[-1:%s:-1] => ' % str(i),
    print s[-1:i:-1]

s[-1:3:-1] =>  
s[-1:2:-1] =>  d
s[-1:1:-1] =>  dc
s[-1:0:-1] =>  dcb
s[-1:None:-1] =>  dcba

Upvotes: 1

senderle
senderle

Reputation: 151077

You can't expect -1 to mean both the final item in the string and the "item before" the first item in the string. That would be inconsistent.

Perhaps you're imagining that Python is treating a string as a loop, and thinking of -1 as if it were simultaneously the "item before" 0 and the last item in the string. But that's not the case. For example, if that were the case, then this would hold:

'abcd'[-2:-1:-1] == 'cbad'

But it doesn't. The result is simply the empty string.

>>> 'abcd'[-2:-1:-1] 
''

The correct interpretation of negative indices in string slicing is as reverse indexing from the end of the string, not as cyclical indexing from 0.

As further food for thought, consider the following:

a = 'abcd'
a[-1:-(len(a) + 0):-1] == 'dcb'
a[-1:-(len(a) + 1):-1] == 'dcba'
a[-1:-(len(a) + 2):-1] == 'dcba'

Upvotes: 1

NPE
NPE

Reputation: 500693

In this context, negative and non-negative indices are two separate classes:

  • non-negative indices start from the beginning;
  • negative indices start from the end.

It seems pretty logical to me that slicing is defined such that the latter never overflow into the former, as you seem to be expecting when you say:

It should run down to one before -1 i.e., index 0

Upvotes: 3

Abhijit
Abhijit

Reputation: 63757

You have missed the whole point of slicing

[start:end:stride] is what a slice operator would look like

if stride is negative, then definitely your start should be greater than end as you are moving from high to low. All your examples which fails violates that.

You should definitely start reading Extended Slicing

Upvotes: 1

Nolen Royalty
Nolen Royalty

Reputation: 18653

s[-1:-1:-1]

Doesn't work for the same reason that

s[0:0]

doesn't give you 'abcd'.

When you slice, you are referring to the space between two elements, not the location of those elements. So you're asking for the space between -1 and -1, which is ''.

Upvotes: 6

jamylak
jamylak

Reputation: 133634

In

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

The start and end are both -1 so they are the same. A slice takes each element in the array from the start to the end as it increases by the step each time. If it has already reached the end then the slice is finished... therefore it returns ''.

Try:

>>> s[1:1:1]
>>> ''

That might help this make more sense as it is almost the same thing, but positive.

Upvotes: 3

Related Questions