Related
In my code I am getting an index error - IndexError: list index out of range. Could you please 1) explain why is this and then 2) make some corrections to my code? Thank you for your answer in advance
x = [1, 2, 3, 4, 5]
for i in range(len(x)):
if x[i] % 2 == 0:
del x[i]
When you use del you reduce the size of your array but the initial loop goes through the initial size of the array, hence the IndexError.
If you want to delete items I recommend using list comprehension:
x = [1, 2, 3, 4, 5]
x_filtered = [i for i in x if i%2]
Use a new list (comprehension) instead:
x = [1, 2, 3, 4, 5]
y = [item for item in x if not item % 2 == 0]
print(y)
# [1, 3, 5]
Or - considered "more pythonic":
y = [item for item in x if item % 2]
This is because you are removing objects inside of the loop, in other words making the list shorter.
Instead use this:
x = x[0::2]
To select every second value of the list
If you want all the even vaues, instead use a list generator:
x = [value for value in x in value%2 == 0]
You are deleting items from the very list you are iterating over. An alternative approach would be:
x = [1, 2, 3, 4, 5]
answer = [i for i in x if i % 2 != 0]
print(answer)
Outputs:
[1, 3, 5]
x = [1, 2, 3, 4, 5]
for i in range(len(x) -1, -1, -1):
if x[i] % 2 == 0:
x.pop(i)
"range function takes three arguments.
First is the start index which is [length of list – 1], that is, the index of last list element(since index of list elements starts from 0 till length – 1).
Second argument is the index at which to stop iteration.
Third argument is the step size.
Since we need to decrease index by 1 in every iteration, this should be -1." - Source
I highly recommend list comprehension however in certain circumstances there is no point and removing through iteration is fine. Up to you~
use while loop instead of for loop if you want to delete some item.
x = [1, 2, 3, 4, 5]
i = 0
while i<len(x):
if x[i]%2==0:
del x[i]
i+=1
print(x)
I am using python 3.6.This program should store the value of indexes of the numbers of one array into another (index starting with 1) For Eg if array is [2,3,1] the next one should be [3,1,2].. but while implemending the list gets changed.
I tried to do with respect to values of 1st array but no use it gets changed when doing the logic.
n = int(input())
arr = input()
l = list(map(int,arr.split(' ')))
arr1= l
print(l)
for i in range(0,n):
print(l[i])
arr1[l[i]-1]=i+1
print(arr1)
Answer should be [4,1,2,3] but answer is [2,1,4,3]
enter code here
You are asking for an array of the indexes of the numbers, but your example shows the indexes +1. It would probably be cleaner to stick with zero indexing.
Nevertheless, if you're looking for a (somewhat) flexible approach, you could do something like this with a list comprehension:
>>> l = [2, 3, 1]
>>> [l.index(i+1) +1 if i+1 in l else None for i in range(max(l))]
[3, 1, 2]
Given an array that's spread out, it will fill with None:
>>> l = [2, 3, 7, 1]
>>> [l.index(i+1) +1 if i+1 in l else None for i in range(max(l))]
[4, 1, 2, None, None, None, 3]
It will silently ignore dupes:
>>> l = [2, 2, 1, 2]
>>> [l.index(i+1) +1 if i+1 in l else None for i in range(max(l))]
[3, 1]
you can do it this way:
x = [2, 3, 1]
ind = [x.index(e) for e in sorted(x)]
# if you want your indices to start from 1
[e+1 for e in ind]
I have a 2d list, for example:
list1 = [[1,2],[3,4],[5,6],[7,8]]
and I want to find the sum of all the numbers at the n'th place of every element.
For example if I want the answer for 0, I would calculate:
my_sum = list1[0][0] + list1[1][0] + list1[2][0]
or
my_sum = 0
place = 0
for i in range(len(list1)):
my_sum += list1[i][place]
return my_sum
Output: 16
Is there a more elegant way to do this? Or one that uses only one line of code?
I mean as fictional code for example:
fictional_function(list1,place) = 16
Since you are looking for a functional solution, consider operator.itemgetter:
from operator import itemgetter
L = [[1,2],[3,4],[5,6],[7,8]]
res = sum(map(itemgetter(0), L)) # 16
For performance and simpler syntax, you can use a 3rd party library such as NumPy:
import numpy as np
A = np.array([[1,2],[3,4],[5,6],[7,8]])
res = A[:, 0].sum() # 16
As a generalization if you want multiple indices (e.g. 0 and 1) you could use reduce combined with and element-wise sum something like this:
from functools import reduce
def fictional_function(lst, *places):
s_places = set(places)
def s(xs, ys):
return [x + y for x, y in zip(xs, ys)]
return [x for i, x in enumerate(reduce(s, lst)) if i in s_places]
list1 = [[1, 2], [3, 4], [5, 6], [7, 8]]
print(fictional_function(list1, 0))
print(fictional_function(list1, 0, 1))
print(fictional_function(list1, *[1, 0]))
Output
[16]
[16, 20]
[16, 20]
The idea is that the function s sums two list element-wise, for example:
s([1, 2], [3, 4]) # [4, 6]
and with reduce apply s to a list of lists, finally filter the result for the intended indices (places) only.
list1 = [[1,2],[3,4],[5,6],[7,8]]
ind = 0
sum_ind = sum(list(zip(*list1))[ind])
The above can be even written as function taking list and the index as input and returns the sum of the common index.
What we do in the above is first we get all the same indexes to individual lists using zip and then chooses which index one has to be summed and passes the same to sum function.
I am trying to write a program that sums the integers in the odd columns of a list
def sum_of_odd_cols(x):
for j in range(len(x)):
odds=[x[k][j] for k in range(len(x)) if j%2!=0]
return sum(odds)
x=[[1,2,5],[3,4,6],[7,8,9]]
print(sum_of_odd_cols(x))
What I get from this is '0', why is this happening?
Also one more question
x=[[1,2,5],[3,4,6],[7,8,9]]
for j in range(len(x)):
col=[column[j] for column in x]
this also seems to create a list of the columns in list x, however I don't understand how this works
is 'column' a built in function in python?
How about:
def sum_of_odd_cols(x):
oddsum = 0
for j in range(len(x)):
oddsum += sum([x[k][j] for k in range(len(x)) if j%2!=0])
return oddsum
x=[[1,2,5],[3,4,6],[7,8,9]]
print(sum_of_odd_cols(x))
This probably isn't the best way of doing it, but it will get your code working. The odds variable was getting overwritten by a new list in each iteration of the loop, and since the final column was empty (it's index is even), the sum was always 0.
The reason it returns 0 is because your odds array is empty at the end of the for loop; because in each iteration of the loop you are resetting odds. If you write your loop the 'long' way, it will return the correct results:
odds = []
for j in range(len(x)):
for k in range(len(x)):
if j % 2 != 0:
odds.append(x[k][j])
If I add some print statements, this is what happens:
j is: 0
k is: 0
k is: 1
k is: 2
j is: 1
k is: 0
Adding: 2 to odds
k is: 1
Adding: 4 to odds
k is: 2
Adding: 8 to odds
j is: 2
k is: 0
k is: 1
k is: 2
>>> odds
[2, 4, 8]
For the second part of your question:
Also one more question
x=[[1,2,5],[3,4,6],[7,8,9]] for j in range(len(x)):
col=[column[j] for column in x]
this also seems to create a list of the columns in list x, however I
don't understand how this works is 'column' a built in function in
python?
No, this is a list comprehension, a short-hand way of constructing lists.
The loop is actually:
col = []
for column in x:
col.append(column[j])
Where j is some other variable (set above the comprehension).
If you are comfortable with NumPy:
import numpy as np
a = np.array([[1,2,3], [1,2,3]])
b = np.sum(a[:,::2], axis=0) # column 0, 2, ...
# b = [2, 6]
b = np.sum(a[:,::2])
# b = 8
c = np.sum(a[:,1::2], axis=0) # column 1, 3, ...
You can do
x = [[1,2,5],[3,4,6],[7,8,9]] # Generate the list
sum([sum(k[1::2]) for k in x]) # Sum the numbers in odd columns
# 14
if you need the combined sum for all the numbers in the odd columns.
Your first question has been answered various times.
As for your second question, think about unzipping your nested list (supposing it is not ragged):
>>> x=[[1,2,5],[3,4,6],[7,8,9]]
>>> [x for x in zip(*x)]
[(1, 3, 7), (2, 4, 8), (5, 6, 9)]
This gives you a list containing the columns.
If the tuples are a problem and you need lists inside the list, use the builtin list:
>>> [list(x) for x in zip(*x)]
[[1, 3, 7], [2, 4, 8], [5, 6, 9]]
So basically your two questions boil down to this:
def sum_of_odd_cols(x):
return sum(sum(x[1::2]) for x in x)
def rows_to_columns(x):
return [list(x) for x in zip(*x)]
So I want to create a list which is a sublist of some existing list.
For example,
L = [1, 2, 3, 4, 5, 6, 7], I want to create a sublist li such that li contains all the elements in L at odd positions.
While I can do it by
L = [1, 2, 3, 4, 5, 6, 7]
li = []
count = 0
for i in L:
if count % 2 == 1:
li.append(i)
count += 1
But I want to know if there is another way to do the same efficiently and in fewer number of steps.
Solution
Yes, you can:
l = L[1::2]
And this is all. The result will contain the elements placed on the following positions (0-based, so first element is at position 0, second at 1 etc.):
1, 3, 5
so the result (actual numbers) will be:
2, 4, 6
Explanation
The [1::2] at the end is just a notation for list slicing. Usually it is in the following form:
some_list[start:stop:step]
If we omitted start, the default (0) would be used. So the first element (at position 0, because the indexes are 0-based) would be selected. In this case the second element will be selected.
Because the second element is omitted, the default is being used (the end of the list). So the list is being iterated from the second element to the end.
We also provided third argument (step) which is 2. Which means that one element will be selected, the next will be skipped, and so on...
So, to sum up, in this case [1::2] means:
take the second element (which, by the way, is an odd element, if you judge from the index),
skip one element (because we have step=2, so we are skipping one, as a contrary to step=1 which is default),
take the next element,
Repeat steps 2.-3. until the end of the list is reached,
EDIT: #PreetKukreti gave a link for another explanation on Python's list slicing notation. See here: Explain Python's slice notation
Extras - replacing counter with enumerate()
In your code, you explicitly create and increase the counter. In Python this is not necessary, as you can enumerate through some iterable using enumerate():
for count, i in enumerate(L):
if count % 2 == 1:
l.append(i)
The above serves exactly the same purpose as the code you were using:
count = 0
for i in L:
if count % 2 == 1:
l.append(i)
count += 1
More on emulating for loops with counter in Python: Accessing the index in Python 'for' loops
For the odd positions, you probably want:
>>>> list_ = list(range(10))
>>>> print list_[1::2]
[1, 3, 5, 7, 9]
>>>>
I like List comprehensions because of their Math (Set) syntax. So how about this:
L = [1, 2, 3, 4, 5, 6, 7]
odd_numbers = [y for x,y in enumerate(L) if x%2 != 0]
even_numbers = [y for x,y in enumerate(L) if x%2 == 0]
Basically, if you enumerate over a list, you'll get the index x and the value y. What I'm doing here is putting the value y into the output list (even or odd) and using the index x to find out if that point is odd (x%2 != 0).
You can also use itertools.islice if you don't need to create a list but just want to iterate over the odd/even elements
import itertools
L = [1, 2, 3, 4, 5, 6, 7]
li = itertools.islice(l, 1, len(L), 2)
You can make use of bitwise AND operator &:
>>> x = [1, 2, 3, 4, 5, 6, 7]
>>> y = [i for i in x if i&1]
[1, 3, 5, 7]
This will give you the odd elements in the list. Now to extract the elements at odd indices you just need to change the above a bit:
>>> x = [10, 20, 30, 40, 50, 60, 70]
>>> y = [j for i, j in enumerate(x) if i&1]
[20, 40, 60]
Explanation
Bitwise AND operator is used with 1, and the reason it works is because, odd number when written in binary must have its first digit as 1. Let's check:
23 = 1 * (2**4) + 0 * (2**3) + 1 * (2**2) + 1 * (2**1) + 1 * (2**0) = 10111
14 = 1 * (2**3) + 1 * (2**2) + 1 * (2**1) + 0 * (2**0) = 1110
AND operation with 1 will only return 1 (1 in binary will also have last digit 1), iff the value is odd.
Check the Python Bitwise Operator page for more.
P.S: You can tactically use this method if you want to select odd and even columns in a dataframe. Let's say x and y coordinates of facial key-points are given as columns x1, y1, x2, etc... To normalize the x and y coordinates with width and height values of each image you can simply perform:
for i in range(df.shape[1]):
if i&1:
df.iloc[:, i] /= heights
else:
df.iloc[:, i] /= widths
This is not exactly related to the question but for data scientists and computer vision engineers this method could be useful.