sum function not working - python

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)]

Related

Specify the consecutive values (zeros) and remove them but only if they are consecutive

I have this list of values:
A = [0,0,1,2,3,4,5,6,0,6,6,8,8,0,0,2,3,4,5,12,45,-0,-0,-9,-2,3,-0,-2,-2,-2]
I want to get this list of values for the output :
A = [1,2,3,4,5,6,0,6,6,8,8,2,3,4,5,12,45,-9,-2,3,-0,-2,-2,-2]
Basically, I want to drop the consecutive zeros only, and keep all the other values.
Do you have any idea on how i can do that ? I tried this one but i know there will be in index error :
X = []
for j in range(len(A)):
if A[j] != 0 and A[j+1] != 0:
X.append(A[j])
else:
print('lol')
print(X)```
You can use itertools.groupby and itertools.chain:
from itertools import groupby, chain
out = list(chain.from_iterable(G for k,g in groupby(A)
if len(G:=list(g))<2 or k!=0))
Explanation:
groupby will group the consecutive values. For each group, if the length is no more than 1 or the key (=value) is not 0, keep it. Finally chain all the groups together and convert to list.
Note that groupby returns iterators so I am using an assignment expression to perform the conversion.
output:
[1, 2, 3, 4, 5, 6, 0, 6, 6, 8, 8, 2, 3, 4, 5, 12, 45, -9, -2, 3, 0, -2, -2, -2]
With itertools:
from itertools import groupby
X = [x
for x, [*xs] in groupby(A)
if x or len(xs) == 1
for x in xs]
Alternatively:
X = []
for x, [*xs] in groupby(A):
if x or len(xs) == 1:
X += xs
Or taking any x that's not zero or where the previous and next values are not zero (padding with 1):
X = [x
for p, x, n in zip([1]+A, A, A[1:]+[1])
if x or p and n]
if u dont want to import itertools and prefer list comprehension
A = [i for index,i in enumerate(A) if i!=0 or index not in [0,len(A)] and A[index-1]!=i and A[index+1]!=i ]
note that this expressions uses the precedence of and operator over or operator
enumerate is used too
Here's a more simple, easy, and bit lengthy than other answers method to solve your problem
A = [0,0,1,2,3,4,5,6,0,6,6,8,8,0,0,2,3,4,5,12,45,-0,-0,-9,-2,3,-0,-2,-2,-2]
ind=[i for i,j in enumerate(A) if j==0]
C=[(ind[i],ind[i+1]) for i in range(len(ind)-1) if ind[i]+1==ind[i+1]]
D=[i for i1 in C for i in i1]
E=["" if i in D else j for i,j in enumerate(A)]
F=[i for i in E if i!=""]
# TEST
d_output=[1,2,3,4,5,6,0,6,6,8,8,2,3,4,5,12,45,-9,-2,3,-0,-2,-2,-2]
print(F==d_output)
Output: 1 i.e Your desired output
If you want to specify the value, then you can wrap it up in a function as below:
def remove_c(list_2,val):
ind=[i for i,j in enumerate(list_2) if j==val]
C=[(ind[i],ind[i+1]) for i in range(len(ind)-1) if ind[i]+1==ind[i+1]]
D=[i for i1 in C for i in i1]
E=["" if i in D else j for i,j in enumerate(A)]
return [i for i in E if i!=""]
print(remove_c(A,10))
Explantion:
I have taken all the indexes of 0 in the list.
Checked if the indexes are consecutive or not. If they are, then append them in the list C in tuple.
And, because the list C contains tuple, created a flat list D out of list C.
Replaced the indexes of list D with "".
Removed "" for the list.
I have noticed a silly mistake in your code:
X = []
for j in range(len(A)): # Mistake here
if A[j] != 0 and A[j+1] != 0: # if we bypassed the above error we can also get error here
X.append(A[j])
else:
print('lol')
print(X)
The problem is when the i is at last index of the list, there would be no other index but you have hard-coded to search for index+1, so it would throw an error.
There are 2 method to solve this:
Use try and except.
Replace range(len(A) to range(len(A)-1).

Python arranging a list to include duplicates

I have a list in Python that is similar to:
x = [1,2,2,3,3,3,4,4]
Is there a way using pandas or some other list comprehension to make the list appear like this, similar to a queue system:
x = [1,2,3,4,2,3,4,3]
It is possible, by using cumcount
s=pd.Series(x)
s.index=s.groupby(s).cumcount()
s.sort_index()
Out[11]:
0 1
0 2
0 3
0 4
1 2
1 3
1 4
2 3
dtype: int64
If you split your list into one separate list for each value (groupby), you can then use the itertools recipe roundrobin to get this behavior:
x = ([1, 2, 2, 3, 3, 3, 4, 4])
roundrobin(*(g for _, g in groupby(x)))
If I'm understanding you correctly, you want to retain all duplicates, but then have the list arranged in an order where you create what are in essence separate lists of unique values, but they're all concatenated into a single list, in order.
I don't think this is possible in a listcomp, and nothing's occurring to me for getting it done easily/quickly in pandas.
But the straightforward algorithm is:
Create a different list for each set of unique values: For i in x: if x not in list1, add to list 1; else if not in list2, add to list2; else if not in list3, ad to list3; and so on. There's certainly a way to do this with recursion, if it's an unpredictable number of lists.
Evaluate the lists based on their values, to determine the order in which you want to have them listed in the final list. It's unclear from your post exactly what order you want them to be in. Querying by the value in the 0th position could be one way. Evaluating the entire lists as >= each other is another way.
Once you have that set of lists and their orders, it's straightforward to concatenate them in order, in the final list.
essentially what you want is pattern, this pattern is nothing but the order in which we found unique numbers while traversing the list x for eg: if x = [4,3,1,3,5] then pattern = 4 3 1 5 and this will now help us in filling x again such that output will be [4,3,1,5,3]
from collections import defaultdict
x = [1,2,2,3,3,3,4,4]
counts_dict = defaultdict(int)
for p in x:
counts_dict[p]+=1
i =0
while i < len(x):
for p,cnt in counts_dict.items():
if i < len(x):
if cnt > 0:
x[i] = p
counts_dict[p]-=1
i+=1
else:
continue
else:
# we have placed all the 'p'
break
print(x) # [1, 2, 3, 4, 2, 3, 4, 3]
note: python 3.6+ dict respects insertion order and I am assuming that you are using python3.6+ .
This is what I thought of doing at first but It fails in some cases..
'''
x = [3,7,7,7,4]
i = 1
while i < len(x):
if x[i] == x[i-1]:
x.append(x.pop(i))
i = max(1,i-1)
else:
i+=1
print(x) # [1, 2, 3, 4, 2, 3, 4, 3]
# x = [2,2,3,3,3,4,4]
# output [2, 3, 4, 2, 3, 4, 3]
# x = [3,7,1,7,4]
# output [3, 7, 1, 7, 4]
# x = [3,7,7,7,4]
# output time_out
'''

Pair two lists in inverse order

What I want to do is to choose one item in list A and another one in list B, pair them like:
A[0]+B[n], A[1]+B[n-1],.....,A[n]+B[1]
I use two for loops but it doesn't work:
class Solution(object):
def plusOne(self, digits):
sum=0
for j in range(len(digits)-1,0,-1) :
for i in range(0,len(digits),1):
sum=sum+digits[i]*pow(10,j)
return sum+1
I inputted [1,2,3] and what I want to get is 124,
but I got 661.
Edit:
Sorry, the example I gave above is not so clear.
Let us think about A[1,2,3] and B[6,5,4].
I want output [5,7,9], because 5 is 1+4, 7 is 2+5, 9 is 3+6
What you are trying to do is turn a list of digits into the according number (and add 1). You can enumerate the reversed list in order to pair a digit with its appropriate power of 10:
digits = [1, 2, 3]
sum(10**i * y for i, y in enumerate(digits[::-1])) + 1
# 124
You can apply that to your other example as follows, using zip:
A = [1,2,3]
B = [6,5,4]
sum(10**i * (x+y) for i, (x, y) in enumerate(zip(B, A[::-1])))
# 579
You can do this without a loop:
A = [1,2,3]
B = [6,5,4]
C = list(map(sum,zip(A,B[::-1]) ))
print(C)
zip() - creates pairs of all elements of iterables, you feed it A and B reversed (via slicing). Then you sum up each pair and create a list from those sums.
map( function, iterable) - applies the function to each element of the iterable
zip() works when both list have the same length, else you would need to leverage itertools.zip_longest() with a defaultvalue of 0.
K = [1,2,3,4,5,6]
P = list(map(sum, zip_longest(K,C,fillvalue=0)))
print(P)
Output:
[5, 7, 9] # zip of 2 same length lists A and B reversed
[6, 9, 12, 4, 5, 6] # ziplongest for no matter what length lists
You only need one loop if you want to search in same list back and forth or different list with same length (i and len(lst)-1-i).
Try not use build-ins such as sum, list, tuple, str, int as variable names, it will give you some nasty result in some case.
class Solution(object):
def plusOne(self, digits):
sum_val = 0
for i in range(len(digits)):
sum_val += digits[i]*pow(10, len(digits)-1-i)
return sum_val+1
sol = Solution()
dig = [1, 2, 3]
print(sol.plusOne(dig))
Output:
124
for A = [1, 2, 3] and B = [6, 5, 4].
You can use a list comprehension:
res = [A[i]+B[len(A)-i-1] for i in range(len(A))]
Or the zip() function and a list comprehension:
res = [a+b for (a, b) in zip(A, reversed(B))]
Result:
[5, 7, 9]

How to set output as a list without space?

n is an integer and xs is a list of integers.
n = 2
xs = [1, 2, 3, 4, 5, 6]
def multiples(n,xs):
empty = []
for i in range(len(xs)):
if xs[i] % n == 0:
print(xs[i])
return empty
It should give me the output of 2, 4, 6 in three separate lines. Is any way I can merge them into a list that without space and only commas?
n=3
xs=[11, 13]
Will the output become '[]', the empty set?
You can just change your for loop to this:
print(",".join(str(x) for x in xs if not x % n))
A generator expression that does it all. I am assuming that your return empty line is just indented incorrectly because at that indentation, it would print only the first one.
You have a couple of problems in your code. The first problem is that you are only checking the first element in your array, and then you are returning out of your function. So, you are never actually completing iterating over your entire list.
Second, you are simply printing your items out, and per your requirements, and based on the fact that you created a list called empty, you want to collect this data and output it when you are finished.
With that being said, what you want to do instead is change your print statement to append to your list:
empty.append(xs[i])
Then when you are finished your for loop return empty.
Like this:
def multiples(n,xs):
empty = []
for i in range(len(xs)):
if xs[i] % n == 0:
empty.append(xs[i])
return empty
Use a list comprehension:
n = 2
xs = [1, 2, 3, 4, 5, 6, 7]
>>> [x for i, x in enumerate(xs, 1) if not i % n]
[2, 4, 6]
xs = [2, 3, 4, 5, 6, 7]
>>> [x for i, x in enumerate(xs, 1) if not i % n]
[3, 5, 7]
n = 3
xs = [11, 13]
>>> [x for i, x in enumerate(xs, 1) if not i % n]
[]
This results in a list of integers instead of strings.
As you want to take every n'th item from your list, you need to use enumerate (starting with a value of 1). The if xs[i] %n == 0 solution just happened to work because the list a continuous range. Try xs = [3, 3, 3, 3] and see what happens with your function and the other solutions...
To help understand what is going on, here is a table of the interim values.
i x i % 2 not i % 2
== == ===== =========
1 3 1 False
2 3 0 True
3 3 1 False
4 3 0 True

Matrix Addition in Python - list

I'm trying to write Matrix Addition function using Python.
Here is the code I've been trying, but it gives me a list index error and I cannot figure out why.
def matrixADD(A,B):
Z = []
#TODO
for i in range(0,len(A)):
for column in range(0, len(A)):
result = A[i][column] + B[i][column]
Z[i][column] = (result)
return Z
using the following lists:
A = [[2,4], [7,0], [6,3]]
B = [[3,1], [-1,8], [-3, 3]]
So in theory, A[0][0] + B[0][0] would equal 5, and I would want to add that value to position Z[0][0].
However I keep receiving the error: IndexError: list index out of range
>>> A = [[2,4], [7,0], [6,3]]
>>> B = [[3,1], [-1,8], [-3, 3]]
>>> Z = [map(sum, zip(*t)) for t in zip(A, B)]
>>> Z
[[5, 5], [6, 8], [3, 6]]
As for how you could fix your current code:
Z = []
for i in range(len(A)):
row = []
for j in range(len(A[i])):
row.append(A[i][j] + B[i][j])
Z.append(row)
The important parts here being that you cannot just assign to Z[i][j] unless that row/column already exists, so you need to construct each inner list separately and append them to Z. Also the inner loop needs to end at the length of a row, so I changed range(len(A)) to range(len(A[i])).
len(A) = 3 but you matrix have dimension 3x2 so when you try to access A[2][2] (because column is between 0 and len(A)) you are out of bounds.
For column you are using range 0 to len(A) (which is 3). A[i][2] will be out of range, because A[i]'s length is only 2.
Try using column range to end a len(A[i]) instead of len(A):
def matrixADD(A,B):
Z = []
#TODO
for i in range(0,len(A)):
for column in range(0, len(A[i])):
result = A[i][column] + B[i][column]
Z[i][j] = (result)
return Z

Categories

Resources