Negative index on nested list - python

Let's say I've got a nested list like this:
mylist = [[],[],[]]
and I want to insert elements at the end of the second nested list:
mylist[1].insert(-1, 1)
mylist[1].insert(-1, 2)
The output i expected was:
[[], [1, 2], []]
but instead I got:
[[], [2, 1], []]
Can somebody explain this to me? I thought the index -1 always pointed to the last position of a list.

according to documentation (https://docs.python.org/3/tutorial/datastructures.html#more-on-lists), the first argument of the insert method is the index of the element before which to insert...and -1 designates the last element of a list: so by calling insert(-1,...) the element you insert will always become the next to last element of your list.
this is easy to veryfy. if you insert yet another element
mylist[1].insert(-1, 3)
you will notice the resulting list becomes
[[], [2, 3, 1], []]
so should probably use append instead. or calculate the index dynamically like
mylist[1].insert(len(mylist[1]), 3)

If a list has for example 3 elements, they are numbered from 0 to 2 (i.e. 0, 1, 2).
If you want use negative indices, they are numbered from -3 to -1 (i.e. -3, -2, -1).
Now, if you want insert a new element at position -1, it is the same, as inserting at position 2, i.e. the inserted element will become element[2].
But element[2] will be then an element of the 4-element list, so its current position in the negative notation is not -1 but -2:
element[-4], element[-3], element[-2], element[-1]

From this page,
list.insert(index, element) means you insert element at index index. .insert(-1, value) means inserting value at the last element of the list (index=len(lst)-1). So
mylist[1].insert(1, 1)
mylist[1].insert(1, 2)
should solve the problem.
Another approach is to use append as the other one said.
mylist[1].append(1)
mylist[1].append(2)

Related

The second to the last line of code is confusing to me

I am quite new to python and programming in general so I am still trying to understand the details in practice. This is a problem I found online so I can practice nested loops more. If my question is missing anything or you do not understand my question, please let me know. I would like to get better at asking good questions as well.
list =[[1, 2], [3,4]]
m = 1
print(list)
for i in range(0, 2):
m *= 10
for j in range(0, 2):
list[i][j] *= m # This part right here.
print(list)
This is what prints on the terminal:
[[1, 2], [3, 4]]
[[10, 20], [300, 400]]
I was trying to go through this block of code step by step to make sure I understand it but this part is stumping me. I understand that the whole function of this nested for loop is to multiply the items in the 1st list with 10 and the 2nd list with 100. I also know what the *= m part is, the part that's confusing to me is the code right before that on the same line.
So far I tried to just copy this specific part in google and see if anything came up. I could not find anything that would make sense. I also tried to just run this whole line and see what printed (list[i][j] *= m)(I changed the variable to numbers obviously). That only came up with a type error... There are no type variables left in list[2]. I was trying to isolate it to see what just this part does but it apparently doesn't work like that. I guess i need to think outside the box a little more maybe.
If we take i to be 1 and j to be 1, list[i][j] would be 4. list[i] = [3,4] so what you're doing is finding index 1 of the list [3, 4]
list is a list containing nested lists.
list[0] is the list [1, 2]. list[1] is the list [3, 4].
When you use two indexes like list[i][j], it first gets the nested list list[i], then accesses the [j] element of that. So when i == 0 and j == 1, this accesses the list element containing 2.
*= m then multiplies that list element. So when i == 0 and m == 10, it multiplies the values in the first sublist by 10. Then when i == 1 and m == 100 it multiplies the values in the second sublist by 100.
list = [[1,2], [3,4]] is an array of arrays.
To get a single element, you have to subscript list twice, which is exactly what list[i][j] is.
list[0] returns [1,2], the 0-th element of the list, which is a sublist
list[0][0] returns 1, the 0-th element of the 0-th sublist
list[0][1] returns 2, the 1st element of the 0-th sublist
.
list[1] returns [3,4], the 1st element of the list, which is a sublist
list[1][0] returns 3, the 0-th element of the 1st sublist
list[1][1] returns 4, the 1st element of the 1st sublist
.
Also, the reason why list[2] doesn't return anything is because list only has two elements, which have the index 0 and 1, so trying to get the element at index 2 will not work

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]

del statement not working for list

I have a long list where each element is a list of length 2. The first element of each is a list is a string and the second element of each list is an integer corresponding to the string.
I want to loop through the long "parent" list and delete any "child" lists where the integer is less than three. This is my code.
for i in range(len(fontsizenum) / 2):
if int(fontsizenum[i][1]) < 3:
del fontsizenum[i]
However, it is not working as when I print the list afterwards, it still contains values with numbers less than three.
Say this is the list that I am altering.
fontsizenum = [[cereal, 1], [dog, 4], [cat, 2], [water, 5]]
The expected output is [[dog, 4], [water, 5]].
However, the actual output for me right now is still the original, unchanged list.
The resulting list still contains unexpected values because you are modifying the list while iterating over it. In almost all cases, you should avoid modifying an iterable while iterating over it.
If you change your code to the following, the resulting list should be what you expect.
new_lst = []
for idx, value in enumerate(lst):
if value[1] >= 3:
new_lst.append(value)
As noted in the comments by #AntonvBR, the above snippet can be simplified to the following list comprehension
[i for i in lst if i[1] > 3]
Example
If lst is set to
[
['forbidden', 1],
['hath', 1],
['causes', 2],
['whose', 3],
]
then the resulting list will be
[['whose', 3]]
Explanation
My code snippet creates a new list that contains elements from the old list. Notably, this allows us to avoid modifying the old list.
I changed the condition in the if-statement to check whether to include, rather than to exclude, an element. Finally, if that check is satisfied, then I append the value to the new list.
You want to use a simple list comprehension for this:
expectedoutput = [i for i in fontsizenum if i[1] >= 3]

function that given a list returns a list of list decreasing

I'd make a function in python, that given a list returns a list of list, in which every element is the list given decreased by one.
Input: list_decreaser([0,3,4,5,6,7,8)
Output: [[0,3,4,5,6,7],[0,3,4,5,6],[0,3,4,5],[0,3,4],[0,3],[0]]
My attempt:
def list_decreaser(list):
listresult = []
for x in range(len(list)-1):
list.remove(list[x])
listresult.append(list)
return listresult
The code appends the same list multiple times. It should append copy of the list.
And use del list[..] instead of list.remove(list[..]) to delete an item at specific index.
def list_decreaser(xs):
listresult = []
for i in range(len(xs)-1, 0, -1): # <--- interate backward
del xs[i]
listresult.append(xs[:]) # <----
return listresult
print(list_decreaser([0,3,4,5,6,7,8]))
Or using list comprehension:
>>> xs = [0,3,4,5,6,7,8]
>>> [xs[:i] for i in range(len(xs)-1, 0, -1)]
[[0, 3, 4, 5, 6, 7], [0, 3, 4, 5, 6], [0, 3, 4, 5], [0, 3, 4], [0, 3], [0]]
BTW, don't use list as a variable name. It shadows builtin list function.
The problem is that you're appending the same list over and over again. You keep mutating the list in-place, but you're never creating a new list. So you end up with a list of N references to the same empty list.
This is the same problem discussed in two FAQ questions. I think How do I create a multidimensional list explains it best.
Anyway, what you need to do is append a new list each time through the loop. There are two ways to do that.
First, you can append a copy of the current list, instead of the list itself:
def list_decreaser(list):
listresult = []
for x in range(len(list)-1):
list.remove(list[x])
listresult.append(list[:]) # this is the only change
return listresult
This solves your problem, but it leaves a few new problems:
First, list.remove(list[x]) is a very bad idea. If you give it, say, [0, 1, 2, 0], what happens when you try to remove that second 0? You're calling list.remove(0), and there's no way the list can know you wanted the second 0 rather than the first! The right thing to do is call del list[x] or list.pop(x).
But once you fix that, you're removing the elements from the wrong side. x is 0, then 1, then 2, and so on. You remove element 0, then element 1 (which is the original element 2), then element 2 (which is the original element 4), and eventually get an IndexError. Even if you fixed the "skipping an index" issue (which is also explained in the FAQ somewhere), you'd still be removing the first elements rather than the last ones. You can fix that by turning the range around. However, there's an even easier way: Just remove the last element each time, instead of trying to figure out which x is the right thing, which you can do by specifying -1, or just calling pop with no argument. And then you can use a much simpler loop, too:
def list_decreaser(list):
listresult = []
while list:
list.pop()
listresult.append(list[:])
return listresult
Of course this appends the last, empty list, which you apparently didn't want. You can fix that by doing while len(list) >= 1, or putting an if list: listresult.append(list[:]), or in various other ways.
Alternatively, you can make new truncated lists instead of truncating and copying the same list over and over:
def list_decreaser(list):
listresult = []
while len(list):
list = list[:-1]
listresult.append(list)
return listresult
Note that in this second version, rather than changing the value stored in list, we're creating a new list and storing that new list in list.
use this
def list_decreaser(list1):
listresult = []
for i in list1:
list1 = list[:-1]
listresult.append(list1)
return listresult

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