Regarding Python's slice notation - python

This line of code
print [0, 1, 2, 3, 4][0:1:1]
returns [0].
However, the following line of code:
print [0, 1, 2, 3, 4][0:0:1]
returns [].
Why is this? Based on this Explain Python's slice notation, my understanding is that the format should be:
a[start:end:step] # start through not past end, by step
So shouldn't [0, 1, 2, 3, 4][0:0:1] start and end at the 0th value, thus returning [0]?

The "end" index of a slice is always excluded from the result; i.e., listy[start:end] returns all listy[i] where start <= i < end (note use of < instead of <=). As there is no number i such that 0 <= i < 0, listy[0:0:anything] will always be an empty list (or error).

The end index in Python's slice notation is exclusive. A slice of [n:m] will return every element whose index is >= n and < m.
To simplify things a bit, try it without the step (which isn't necessary when the step value is 1):
>>> a = [0, 1, 2, 3, 4]
>>> a[0:1]
[0]
>>> a[0:0]
[]
As a general rule, the number of elements in a slice is equal to the slice's start index minus the slice's end index. I.e., the slice [n:m] will return m-n elements. This agrees with the one element (1-0) returned by [0:1] and zero elements (0-0) returned by [0:0].
(Note that this is not true if either of the slice indices is outside of the size of the array.)
For a nice visualization of how slice indices work, search for "One way to remember how slices work" at http://docs.python.org/2/tutorial/introduction.html

Note that is [0:0:1] not [0:1:1]
So:
start = 0
end = 0
step = 1
The slice [start:end:step] means it will return values that are between start and end - 1 with a certain step, so for your example:
...[0:0:1]
Values between 0 and -1, so it doesn't return anything.

Related

Last value not showing up after slicing list

Av = [32,5,3,1,3,4,5]
A = Av[0:int(len(Av)/2)]
B = Av[int(len(Av)/2):-1]
print(A,B)
When I run this block of code, I get
[32, 5, 3] [1, 3, 4]
The last value of Av is 5. But it is not showing up on the list B..
It's because you have sliced the list till -1 which means the last element of the array and is excluded from the sliced array.
To get an array sliced till the end leave the end part of the slice code empty. Like this -
B = Av[int(len(Av)/2):]
In python when you use index slicing Av[a:b] you get the elements from position a (included) to position b (excluded). Because -1 refers to the last position, if you do Av[a:-1], the last element won't be included.
If you want to include the last element, just omit the final index -1, that is use Av[a:]. Your code should be like this:
Av = [32,5,3,1,3,4,5]
A = Av[0:int(len(Av)/2)]
B = Av[int(len(Av)/2):]
print(A,B)
Take a look at https://stackoverflow.com/a/509295/7558835 answer. It explains very clearly how does index slicing work.
When you use the slice [x:-1], it doesn't include the value at index -1 (last position), because it is non-inclusive.
Instead, use [x:], which will give a slice that includes x and all values to its right:
B = Av[int(len(Av)/2):]
Output:
>>>B
>>>[1, 3, 4, 5]

Slice a python list from an end index to some begin index [duplicate]

Consider the following simple python code
>>> L = range(3)
>>> L
[0, 1, 2]
We can take slices of this array as follows:
>>> L[1:3]
[1, 2]
Is there any way to wrap around the above array by shifting to the left
[1, 2, 0]
by simply using slice operations?
Rotate left n elements (or right for negative n):
L = L[n:] + L[:n]
Note that collections.deque has support for rotations. It might be better to use that instead of lists.
Left:
L[:1], L[1:] = L[-1:], L[:-1]
Right:
L[-1:], L[:-1] = L[:1], L[1:]
To my mind, there's no way, unless you agree to cut and concatenate lists as shown above.
To make the wrapping you describe you need to alter both starting and finishing index.
A positive starting index cuts away some of initial items.
A negative starting index gives you some of the tail items, cutting initial items again.
A positive finishing index cuts away some of the tail items.
A negative finishing index gives you some of the initial items, cutting tail items again.
No combination of these can provide the wrapping point where tail items are followed by initial items. So the entire thing can't be created.
Numerous workarounds exist. See answers above, see also itertools.islice and .chain for a no-copy sequential approach if sequential access is what you need (e.g. in a loop).
If you are not overly attached to the exact slicing syntax, you can write a function that produces the desired output including the wrapping behavior.
E.g., like this:
def wrapping_slice(lst, *args):
return [lst[i%len(lst)] for i in range(*args)]
Example output:
>>> L = range(3)
>>> wrapping_slice(L, 1, 4)
[1, 2, 0]
>>> wrapping_slice(L, -1, 4)
[2, 0, 1, 2, 0]
>>> wrapping_slice(L, -1, 4, 2)
[2, 1, 0]
Caveat: You can't use this on the left-hand side of a slice assignment.

Reversed array slice including the first element [duplicate]

This question already has answers here:
Python reverse-stride slicing
(8 answers)
Closed 4 years ago.
Let's say I have:
>>> a = [1, 2, 3, 4]
And I want to get a reversed slice. Let's say I want the 1st and 0th elements given start_idx = 1 and stop_idx = 0:
[2, 1]
Using the slice notation:
a[x:y:z]
What values do I use for x, y, and z using start_idx and stop_idx?
I've tried:
>>> a[start_idx:stop_idx:-1]
[2]
>>> a[start_idx:stop_idx-1:-1]
[]
Differentiation:
This question is about a slice with a negative step where the both start and end indexed elements should be included (like a closed interval in math), and the slice end index is dynamically calculated.
Understanding Python's slice notation
is a generic generic question on notation: what x, y, and z mean in a[x:y:z]. It doesn't mention the reversal case.
This question differs from the other flagged duplicates as it deals with the general case where the reversed slice begin and end indices are either calculated or given by variables rather than hard coded.
You can omit the second index when slicing if you want your reversed interval to end at index 0.
a = [1, 2, 3, 4]
a[1::-1] # [2, 1]
In general whenever your final index is zero, you want to replace it by None, otherwise you want to decrement it.
Due to indexing arithmetic, we must treat those cases separately to be consistent with the usual slicing behavior. This can be done neatly with a ternary expression.
def reversed_interval(lst, i=None, j=None):
return lst[j:i - 1 if i else None:-1]
reversed_interval([1, 2, 3, 4], 0, 1) # [2, 1]
Here are two generic solutions:
Take the forward slice then reverse it:
>>> a[stop_idx:start_idx+1][::-1]
[2, 1]
Based on this answer, use a negative step and stop 1 element before the first element (plus the stop offset):
>>> a[start_idx:stop_idx-len(a)-1:-1]
[2, 1]
Comparing execution times, the first version is faster:
>>> timeit.timeit('foo[stop_idx:start_idx+1][::-1]', setup='foo="012345"; stop_idx=0; start_idx=3', number=10_000_000)
1.7157553750148509
>>> timeit.timeit('foo[start_idx:stop_idx-len(foo)-1:-1]', setup='foo="012345"; stop_idx=0; start_idx=3', number=10_000_000)
1.9317215870250948

Are the capabilities python list slicing really asymmetric?

Consider the following code:
>>> a = [0, 1, 2]
>>> for i in range(len(a)):
>>> print a[0:i]
[]
[0]
[0, 1]
However, when I flip the code to take slices from the other end of the list, it no longer works:
>>> for i in range(len(a)):
>>> print a[-i:]
[0, 1, 2]
[2]
[1, 2]
The only way to make the second piece of code to work seems to be to reverse the list, do it the first way, and reverse each piece before printing it. Is there a better way to do this? I use this type of loop sometimes and I would like my code to be as clean as possible.
EDIT: In both loops, I am iterating from left to right. If I flip the direction of iteration as well for the second loop, it works. If I flip the direction of iteration for the first loop, it also has the same hiccup as the second loop:
>>> for i in range(len(a)):
>>> print a[i-1::-1]
[2, 1, 0]
[0]
[1, 0]
The first iteration, you are slicing as -0, which is just the same as slicing from 0. Only the second iteration do you slice as -1, then -2.
Perhaps you could use a range starting at a negative index:
for i in range(-len(a), 0):
print a[-i:]
Reversed slicing cannot be fully symmetric in Python because of 0-based-indexing. Specifically, it isn't possible to distinguish -0 from 0. But the symmetrical access use-case in 0-based-indexed arrays would dictate that if the 0th item is first from the left, then the -0th item (that is, negative 0) is the first from the right, but since 0 and -0 are the same entity, this poses a problem.
Consider the two orientations of a list's indices:
Forward: first item is at position 0, second item at position 1, ..., last item at position n-1
Backward: first item is at position -1, second at -2, ..., last item at position -n
The negative index notation is therefore a shorthand for (length-index): collection[-i] == collection[len(collection) - i]
Or, side by side, the indexing is:
[0, 1, 2,...,n-1]
[-n,..., -3, -2, -1 ]
Where both of the above indices are in fact identical.
To perform a symmetrical operation, your slice operator needs to correctly account for this indexing scheme:
original slice: a[0:i] == i elements from left end (at 0) with step size of 1 == a[0:i:1]
reverse slice: i elements from right end (at -1) with step size of -1.
Thus, the correct slice from the other end would be a[-1:-1-i:-1]
Note that the stop value here is the negative of i, offset by -1 to account for the -1-based-reversed-indexing, which is necessary as we are generating i using a forward based list (e.g. the range function.)
a = range(3) # [0,1,2]
for i in range(len(a)):
# forward case, next to backward case
print a[:i], a[-1:-1-i:-1]
# [] []
# [0] [2]
# [0, 1] [2, 1]

Python: access list value by reference

Very basic question here (I've just started with Python).
I have a list object. It contains five numbers [3,6,2,3,1]
I want find the sum of the first, third and fourth numbers in the list.
What is the syntax?
You can for instance sum elements #1, #3, and #4 with the flexible expression
sum(my_list[i] for i in (0, 2, 3))
The index of the first element is 0 [not 1], etc., i.e. my_list[0] is the first element (with value 3, in the original question), etc.
The items of a list are numbered like this:
a = [3, 6, 2, 3, 1]
^ ^ ^ ^ ^
index 0 1 2 3 4
To access the item with the index i, use a[i]. From here, you should be able to figure out how to sum the desired items.
Just write the index in brackets. Note that the index starts with zero:
lst[0] + lst[2] + lst[3]
In some cases, you can use the sum function and select a slice of the list. For example, to get the sum of the first, third, and fifth element, use:
sum(lst[::2])
You can access an element of a Python list by index by appending [list_index] to the list object (replace list_index with the index you want). For example:
my_list_object = [3,6,2,3,1]
my_sum = my_list_object[0]+my_list_object[2]+my_list_object[3]

Categories