Python 3.x indexing and slicing - python-3.x

I have been confused with python indexing and slicing of data structure(lists,etc.). Let me explain the problem. Suppose I have a python list as shown below.
examplelist = ['ram', 'everest' , 'apple', 32, 'cat', 'covid', 'vaccine', 19]
Example one
>> examplelist[-5 : 7 : -1]
>> [ ]
The result is empty set as shown above. Logic, explained in the python tutorial websites, I have checked is the starting count(-5) indicates item 32. End count 7 indicates one item before the stop/end count which is item 'vaccine'. Step size is -1 which means we need to move right to left. But since our starting item is 32 and end item is 'vaccine' there won't be any item if we move leftwards from 32. Hence the result empty list. OK, agreed. Now lets see another example.
Example Two
>> examplelist[::-1]
>> [19, 'vaccine', 'covid', 'cat', 32, 'apple', 'everest', 'ram']
This is quite commonly used to reverse a list in python data structure. If we use the same logic provided for example 1, how can this example have a reversed list. Logically, with starting count 0(meaning start item is 'ram') and end count all the way until the end of the list and with step size -1 means here too we need to move leftwards from starting item i.e. 'ram'. This too has no items in it if we use the same logic. But this example seems to work differently. Why? Is it that reversing a list is an exception to the logic behind python indexing/slicing.
Now lets see another example below.
Example Three
>> examplelist[:-3:-1]
>> [19, 'vaccine']
In this example our starting count is 0 (so we begin at first item i.e. 'ram'), end count is -3 which refers to one item before the end count i.e. item 'cat' and with step size -1 we move leftwards from start to end item. If we follow the logic there is no item to pick if we move leftwards from our starting item to end item. But the answer list is quite different.
My Confusion
I feel that there is no coherent logic working in all examples. Why does the same logic fails to different problem? My understanding it that there is always a standard logical explanation while coding. I tried to figure out some standard logic that will explain all types of indexing/slicing problem with python lists. But with examples listed above, my confusion still persists. Is it that there is a hole in my understanding or there is some standard explanation to this problem which I have not understood yet? Someone please rescue.

Using a negative step reverses default start and end values for a slice.
These are all equal:
examplelist[-5:7:-1]
examplelist[len(examplelist)-5 : 7 : -1]
examplelist[3 : 7 : -1]
And so are all these:
examplelist[::-1]
examplelist[-1::-1]
examplelist[len(examplelist)-1 : -len(examplelist)-1 : -1]
examplelist[7 : -9 : -1]
As well as these:
examplelist[:-3:-1]
examplelist[len(examplelist)-1 : -3 : -1]
examplelist[7 : 5 : -1]
Once you have positive start and end values, it becomes clear what is happening.
In the second example end value must be negative because there is no other way to represent the element before the first element.

Related

Python list slice [0:-1:-1]

I ran into this statement while I was coding:
l = [1,2,3]
print(l[0:-1:-1])
I was expecting this piece of code gives me [1] however it gives me [], makes me think I must have mis-understood python slice operation, can someone explain what is going on here?
In a slice,
The first integer is the index where the slice starts.
The second integer is the index where the slice ends.
The third integer specifies a stride or step causing the resulting slice to skip items. -1 for reverse the output.
l[0:-1:-1]
is equivalent to
l[len(l)-1:len(l)-1:-1]
The first index converted 0 to len(l)-1, because you added -1 in the last index to reverse the list. This will always give you an empty list.
When you use slice in python and you type
l[x:y:-1]
it would somehow be equivalent to
l.reverse()
print(l[y:x])
l.reverse()
but with the difference that -1 reverses the list elements with their indexes
so if you type
l=[1, 2, 3]
l[2:0:-1]
the output will be
[3, 2]
The reason for empty list is that you change the order of indexes so it wont find any element in that window...
I gathered some information after talking with friends about this problem, now we kind of believe this is what happened: when I do l[0:-1:-1], the first thing interpreter will do is to convert that second -1 to the positive index, which is 2 in my case. Then it will iterate backward with the terminating condition being "start <= end", in this case since at the very beginning it will find 0 <= 2, so it will directly terminate, results in the output array being empty.
I didn't really get what the two other answers are saying here (silly me), maybe they are right, I need to look into the python source code for a 100% certain explanation, but for now I believe what I just stated here is the case.

What does this syntax mean in Python 3?

I've been seeing this syntax, but I'm not quite sure what it means. It's when two square brackets are next to the name of one list. I'm assuming this does some type of list slicing?
mylist[x][y]
mylist[][]
These are just some examples of what I've seen. (I've used variables x&y to represent an arbitrary number)
This notation can be used when the list contains some other lists as elements, which is helpful to represent the matrices. For example:
a=[[1,2,3],[4,5,6],[7,8,9]]
a[0][0] #This gives the number 1.
In this case, a[0] (the first index) chooses the 1st element, which is [1,2,3]. Then the second index (a[0][0]) chooses the first element of the list defined by a[0], thus giving the answer 1.
The top line just indexes into a list within a list. So for example, you could have
mylist = [
[1,2,3],
[4,5,6],
[7,8,9],
]
value = mylist[1][2]
which will get the value 6.
The bottom line doesn't look like valid Python to me.
EXPLANATION:
Consider that mylist[1] just extracts the second element from mylist (second because of 0-based indexing), which is [4,5,6]. Then adding [2] looks up the third item in that list, which is 6. You could also write
inner_list = mylist[1]
value = inner_list[2]
or
value = (mylist[1]) [2]
which both do the same thing.

TypeError summing a list of integers

I'd like to find the sum of the elements in a list using a loop. I must be able to apply this generically if inputting different lists.
I have tried the simple
print(sum(numbers))
and it returns
TypeError: unsupported operand type(s) for +: 'int' and 'str'.
When I tried adding each individually, I found out that the list changes. The original list is [1, 3, 5, 7, 9]. When I added each element using
int(numbers[0]) + int(number[1]) # ...
when I get to index 4, there isn't a value for the index.
I'm a little unsure by what you mean, because you haven't included much code, but I believe I can answer part of it.
It's hard to know why you're having indexing errors without seeing the code you wrote, but I imagine Because you may have been removing them as you added them up.
Maybe try using an accumulator variable, which would result in python code that might look like
numbers = [1,2,3,4]
total = 0
for i in range(len(numbers)): #loops through for exactly the number of items in the list
sum = total + numbers[i]
This won't change any of the items in the list, leaving intact, and leaving you with the variable sum that is equal to the total sum of the list.

Connect string value to a corresponding variable name

This question has somehow to do with an earlier post from me. See here overlap-of-nested-lists-creates-unwanted-gap
I think that I have found a solution but i can't figure out how to implement it.
First the relevant code since I think it is easier to explain my problem that way. I have prepared a fiddle to show the code:
PYFiddle here
Each iteration fills a nested list in ag depending on the axis. The next iteration is supposed to fill the next nested list in ag but depending on the length of the list filled before.
The generell idea to realise this is as follows:
First I would assign each nested list within the top for-loop to a variable like that:
x = ag[0]
y = ag[1]
z = ag[2]
In order to identify that first list I need to access data_j like that. I think the access would work that way.
data_j[i-1]['axis']
data_j[i-1]['axis'] returns either x,y or z as string
Now I need to get the length of the list which corresponds to the axis returned from data_j[i-1]['axis'].
The problem is how do I connect the "value" of data_j[i-1]['axis'] with its corresponding x = ag[0], y = ag[1] or z = ag[2]
Since eval() and globals() are bad practice I would need a push into the right direction. I couldn't find a solution
EDIT:
I think I figured out a way. Instead of taking the detour of using the actual axis name I will try to use the iterator i of the parent loop (See the fiddle) since it increases for each element from data_j it kinda creates an id which I think I can use to create a method to use it for the index of the nest to address the correct list.
I managed to solve it using the iterator i. See the fiddle from my original post in order to comprehend what I did with the following piece of code:
if i < 0:
cond = 0
else:
cond = i
pred_axis = data_j[cond]['axis']
if pred_axis == 'x':
g = 0
elif pred_axis == 'y':
g = 1
elif pred_axis == 'z':
g = 2
calc_size = len(ag[g])
n_offset = calc_size+offset
I haven't figured yet why cond must be i and not i-1 but it works. As soon as I figure out the logic behind it I will post it.
EDIT: It doesn't work for i it works for i-1. My indices for the relevant list start at 1. ag[0] is reserved for a constant which can be added if necessary for further calculations. So since the relevant indices are moved up by the value of 1 from the beginning already i don't need to decrease the iterator in each run.

Unpacking With List vs. Brackets, Giving Unexpected Output Python 3.5.2

Here is what I'm trying to do:
l1 = (3, 4, 3)
l2 = (1, 2, 3)
print(*{x+y, for x,y in zip(l1,l2)})
Output:
4 6
The output I expected was 4 6 6
I may be mistaken, but I think it has to do with the unpacking with brackets because the code below:
print(*list(x+y for x,y in zip(l1,l2)))
Outputs:
4 6 6
Which is what I wanted. I was wondering, if anyone could explain the difference between brackets and list when being unpack?
What you have in the first situation, using {}'s is a set. A set is a class for: unordered collections of unique elements. It didn't print out another 6 because sets only contain unique elements.
In the second case you create a generator which can contain non-unique or unique elements and therefore gives you all of the elements you added to it.
When in doubt, use the function type(), i.e. type(< thing you don't understand goes here >) to find out what you're dealing with.

Resources