indexing list with len(list) vs len(list) - 1 [duplicate] - python

This question already has answers here:
Understanding slicing
(38 answers)
Closed 9 years ago.
#!/usr/bin/python
list2 = ['Bangalore','Cochin','Trivandrum','Auckland','Seoul','Los Angeles']
list2[5] = 'Hamilton'
list2.append('Sydney')
list2.append('San Jose')
list2.append('Amsterdam')
print "Cities = ",list2[0:(len(list2) - 1)]
print "Cities = ",list2[0:(len(list2))]
The first print statement does not print the last element in the list.The second print statement does print all the elements in the list without an out of bounds errors.From the documentation I understand len() simply returns the number of elements in the list.Then why is the last index not len(list) - 1

List slicing never throws an out-of-bounds error:
list2[0:1234567890]
is legal, as is
list2[-1:-1]
Note that when slicing, the upper bound is not included in the slice:
>>> list2[0:1]
['Bangalore']
>>> list2[0:0]
[]
so the slice list2[0:len(list2)] contains exactly the same elements as list2 without slicing, but does return a new list.
Some other remarks:
If you omit the start value, it defaults to 0, and the end value, if omitted, defaults to the length of the list. Thus, list2[0:len(list2)] can be written as list2[:].
negative values count from the end. list2[:len(list2)-1] can be written as list2[:-1].

Because the upper bound is not inclusive. That means if your list has 1 element, you need to put 1, not 0, to include it in the slice. list[0:0] is effectively an empty slice, and if the upper bound was inclusive, there would be no way to get an empty slice. To get a slice with the first element only, you'll need list[0:1] instead.
(I'm using a list with just 1 element because it's super simple to understand. It obviously holds for lists with more items.)

Related

Syntax for range function in Python [duplicate]

This question already has answers here:
Understanding slicing
(38 answers)
Closed 2 months ago.
the range function has syntax range(start,stop,step) and returns a sequence based on the arguments. Please explain the syntax range(10)[2:6][2]
range(10) is identical to range(0,10,0). what is happening with '[2:6][2]?
thanks
entering range(10)[2:6][2] evaluates to 4, but I don't understand why.
range(param) is a build-function that generate a list. The param is the lenght of number of list.
So you have a list of 10 numbers. From 0 to 9. Remenber arrays become at the 0 position.
Then you slice the list with [start,end, jumps]. You slice the list.
The result is 2,3,4,5.
After that you call the number at position [2].
Beginning from 0 => 2
Next position 1 => 3
Then position 2 => 4
The range function in Python has the syntax range(start, stop, step) and generates a sequence of numbers starting from start, up to but not including stop, with a step size of step. In the case of range(10), this generates a sequence of numbers starting from 0 and up to but not including 10, with a step size of 1. Note that the default value for the start parameter is 0 and the default value for the step parameter is 1, so range(10) is is identical to range(0,10,1) rather than range(0,10,0) as you indicated in your post.
You can find documentation for the range built-in function at: http://docs.python.org/3/library/functions.html#func-range and https://docs.python.org/3/library/stdtypes.html#typesseq-range
The square brackets after the range function are used to index the resulting sequence. For example, range(10)[2:6] returns a sub-sequence of numbers starting from the 3rd element (index 2) and up to but not including the 6th element (index 5), which in this case is [2, 3, 4, 5].
The second set of square brackets then indexes this sub-sequence, returning the 3rd element. Therefore, the expression range you provided evaluates to 4.
You can find documentation for the slicing syntax at: https://python-reference.readthedocs.io/en/latest/docs/brackets/slicing.html

Strange slicing behavior in Python

I found this to be a bit strange. Can anyone explain to me: Why, if I have a list like this:
l = [1, 2, 3, 4, 5]
and I do this reassignment:
l[-1:0] = [99,]
then it inserts the 99 to the left of the 5, like so:
[1, 2, 3, 4, 99, 5]
We must assign to an iterable [99,], assigning to just the integer 99 will give an error, which might be a clue as to what's happening here... I guess?
According to the official Docs:
In the table s is an instance of a mutable sequence type, t is any iterable object and x is an arbitrary object that meets any type and value restrictions imposed by s
Note (1): t must have the same length as the slice it is replacing.
So, if you do l[-1] = 99, you are replacing the item in position -1 (that means, one less than the last) to the value 99.
On the other hand, if you do l[-1:0] = [99,], you taking the elements from index -1 to 0 (that means, a slice of length zero in the position -1), and replacing those by the elements of [99,] (that is why it must be an iterable), which effectively is a semantic insert.
When you slice a Python list with [start:end] you end up with another list. The beginning of the new list in your example is the location of the last element in your original list. Just because the value of l[-1:0] in your example is [] it does not mean that this is simply an empty list. Its value is an empty list, but the reference to l[-1:0] is to a sliced list within an existing list.
So in your example
l = [1,2,3,4,5]
# ^ l[-1:0] starts here but the size is 0
When you assign a list to a sliced position of another list, you are effectively performing list concatenation.
This is the equivalent of what you are doing.
l=[1,2,3,4,5]
l[4:0] = [99] # concatenate a new list at the position of the final element in the original list
# A different way to look at it
l[0:4] + [99] + l[4:]
The result again is effectively concatenating the two lists. More specifically, you are inserting the elements of a new list into the original at the position you've indicated. Using a literal integer such as 99 will result in an error because you cannot concatenate an int and a list directly. However, as others have pointed out, a slice assignment can use any iterable, so l[-1,0] = (99,) works by the same principle.
First, you'll need to know how the slicing works fully. You can have 3 values:
[start:end:step]
In your code, l[-1:0], using -1 as the start value will aim at the last value in the list, but it'll also try and find a list of values because of the end value being set. This is why you had to use a list to change the value.
To solve this issue, use l[-1] = 99 to change the last value of the list to 99 (assuming that's the intended result)

Logic behind Python reversing a slice with index and step [duplicate]

This question already has answers here:
Understanding slicing
(38 answers)
Closed 6 years ago.
I'm trying to understand the logic behind reversing a slice using slice index and step.
First of all, I can reverse a string using the slice step like this:
a = "Hello"
a[::-1]
>>> 'olleH'
Also, I can reverse only a part of the string like this:
a = "Hello"
a[:2:-1]
>>> 'ol'
But when I try to reverse the string using another range like this:
a = "Hello"
a[1:3:-1]
>>> ''
I get an empty string.
However, if I inverse the ranges like this example:
a = "Hello"
a[4:1:-1]
>>> 'oll'
I get the reversed slice between indexes 1 and 4.
But, correct me if I'm wrong, I know that the first index from a slice must be less than the second index.
This is why when I run this example:
a = "Hello"
a[4:1]
>>> ''
I get an empty string.
So, can somebody explain to me why reversing a string (slice) while an inversed range with a negative step works, and using the logic of the first index being less than the second one in a slice will give an empty string.
Thanks for your answers.
It is not the case that the first number has to be less than the second, it just is the starting index, while the second is the ending index. Therefore, when you are going backwards (third index is -1), the starting index should be larger than the ending index, otherwise you'll get an empty string.
The syntax is
a[begin;end;step]
So when you use step -1 it will traverse through the string backwards and thus begin should be bigger than the end.
If you omit step it defaults to 1 and will traverse through the string forward and should begin must be smaller than the end.
Fun fact, you can also traverse in steps of -2
a = 'Hello, world!'
a[::-2] # => '!lo olH'

What is the meaning of "int(a[::-1])" in Python? [duplicate]

This question already has answers here:
Understanding slicing
(38 answers)
Closed 4 years ago.
I cannot understand this. I have seen this in people's code. But cannot figure out what it does. This is in Python.
str(int(a[::-1]))
Assuming a is a string. The Slice notation in python has the syntax -
list[<start>:<stop>:<step>]
So, when you do a[::-1], it starts from the end towards the first taking each element. So it reverses a. This is applicable for lists/tuples as well.
Example -
>>> a = '1234'
>>> a[::-1]
'4321'
Then you convert it to int and then back to string (Though not sure why you do that) , that just gives you back the string.
The notation that is used in
a[::-1]
means that for a given string/list/tuple, you can slice the said object using the format
<object_name>[<start_index>, <stop_index>, <step>]
This means that the object is going to slice every "step" index from the given start index, till the stop index (excluding the stop index) and return it to you.
In case the start index or stop index is missing, it takes up the default value as the start index and stop index of the given string/list/tuple. If the step is left blank, then it takes the default value of 1 i.e it goes through each index.
So,
a = '1234'
print a[::2]
would print
13
Now the indexing here and also the step count, support negative numbers. So, if you give a -1 index, it translates to len(a)-1 index. And if you give -x as the step count, then it would step every x'th value from the start index, till the stop index in the reverse direction. For example
a = '1234'
print a[3:0:-1]
This would return
432
Note, that it doesn't return 4321 because, the stop index is not included.
Now in your case,
str(int(a[::-1]))
would just reverse a given integer, that is stored in a string, and then convert it back to a string
i.e "1234" -> "4321" -> 4321 -> "4321"
If what you are trying to do is just reverse the given string, then simply a[::-1] would work .

Why does somelist[len(somelist)] generate an IndexError but not somelist[len(somelist):]?

I understand that somelist[len(somelist)] cannot access an index that is outside of the defined list - this makes sense.
But why then does Python allow you to do somelist[len(somelist):]?
I've even read that somelist[len(somelist):] = [1] is equivalent to somelist.append(1)
But why does slice notation change the fact that the index "len(somelist)" is still outside the range of the list?
Here's something from the documentation. There are specific rules around slicing of any iterable; of particular note is #4, emphasis mine:
The slice of s from i to j is defined as the sequence of items with
index k such that i <= k < j. If i or j is greater than len(s), use
len(s). If i is omitted or None, use 0. If j is omitted or None, use
len(s). If i is greater than or equal to j, the slice is empty.
There's nothing at the index len(somelist) (list indices start at 0 in python). Therefore, trying to access a non-existing element raises an error.
However, list slicing (with the myList[i:] syntax) returns a new list containing the elements including and after i. Since there are no elements in the list at index i (or after), an empty list is returned
From the Python docs:
Degenerate slice indices are handled gracefully: an index that is too large is replaced by the string size, an upper bound smaller than the lower bound returns an empty string.
So an index > list size is automatically corrected, and somelist[len(somelist):] returns the elements after the last one, ie nada.

Categories