Take 2 dimensional list from user input - python

CODE SNIPPET
n = int(raw_input())
a = [[0]*n]*n
for i in xrange(0,n):
s = raw_input()
for j in xrange(0,n):
a[i][j] = int(s[j])
print a
I am new to python. While taking user input from stdin, I gave the following values in stdin
3
101
010
101
But when I print, the output comes as
[[1, 0, 1], [1, 0, 1], [1, 0, 1]]
Whereas the output should be
[[1, 0, 1], [0, 1, 0], [1, 0, 1]]
Can someone please guide me what am I missing?
I am using python 2.7.

First you define matrix with full range like
a = [[0 for i in range(n] for i in range(n)]
a[i][j] = any value
I hope it's work

Change a to this :
a = [[0 for i in range(n)] for j in range(n)]
Because [[0]*n]*n will create a single instance each time, so it will take the last assigned value to all instances because they are same referring to.They're all the same exact list in memory. When you use the [[0]*n]*n syntax, what you get is a list of n many [0] objects, but they're all references to the same object. They're not distinct instances, rather, just n references to the same instance.

Try the following code. Obviously you would need to add a lot of checks.
n_rows = int(raw_input('Enter Number of rows required: '))
n_cols = int(raw_input('Enter Number of cols required: '))
rows = []
for i in range(0, n_rows):
row = int()
final_list = []
for i in xrange(0, n_rows):
s = list(raw_input('Enter the values for row no. {} (Separated by commas): '.format(i+1)))
s_list = [int(i) for i in s if i != ',']
if len(s_list) != n_cols:
raise ValueError('Number of values entered are not correct')
else:
final_list.append(s_list)
print final_list
Or you can also try the Numpy Module

Here is the problematic line:
a = [[0]*n]*n
This, counterintuitively, creates only a single instance of [0, 0, 0] and makes three references to it. That means it is overwritten by your last input each time.
You can solve it by instead writing:
a = [[0 for _ in range(n)] for _ in range(n)]

Related

Extra zeros appear at the end of existing items when appending new lists to a list

I'm trying to solve Pascal triangle prblem on leetcode: "Return a given number of Pascal triangle rows". I've defined a function getNextRow(row) that calculates the next rows given the current one and then calling it a certain number of times and appending these rows to my resulting list. For some reason extra zero appears at the end of the previous row each time I'm adding a new row.
E.g.
Input: 5 #5 rows needed
Output: [[1,0],[1,1,0],[1,2,1,0],[1,3,3,1,0],[1,4,6,4,1]]
Expected output: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]
def getNextRow(row):
res = [1]
if len(row) == 0:
return res
row.append(0)
for i in range(len(row) - 1):
res.append(row[i] + row[i+1])
return res
def generate(numRows):
pascal = [] #Empty resulting triangle
currentRow = []
num = 0 #Counter
while num < numRows:
currentRow = getNextRow(currentRow)
pascal.append(currentRow)
num += 1
return pascal
if __name__ == '__main__':
print(generate(5))
The issue here is because you are reusing the variable currentRow on each iteration. In the fourth line of the getNextRow function, you are appending 0 to the row passed in to the variable. This is directly referencing the currentRow variable in memory and therefore making changes before the currentRow is added to the pascal list. To fix this, you can either copy the currentRow before you add it to the pascal list e.g:
pascal.append(currentRow.copy())
or copy the row variable within getNextRow like so:
def getNextRow(row):
row = row.copy()
Hope this helps!
You append zero to row in getNextRow(). That entry in the list never gets modified so you'll always see a redundant trailing zero.
Your code is also rather cumbersome. Here's a more concise implementation:-
def pascal(n):
r = [[1]]
for i in range(2, n+1):
p = r[-1]
r.append([1] + [p[j-1] + p[j] for j in range(1, i-1)] + [1])
return r
print(pascal(6))
Output:
[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1]]

Finding all non-negative integers that add up to a particular value or less, with number of integers changing

I am working in Python. I want to make a function that takes two values: maxSum and n. The output should be all the n-tuples of non-negative integers that add up to maxSum or less. For example, if maxSum is 2 and n is three, the output should be:
[[0, 0, 0], [0, 0, 1], [0, 0, 2], [0, 1, 0], [0, 1, 1], [0, 2, 0], [1, 0, 0], [1, 0, 1], [1, 1, 0], [2, 0, 0]]
For any given value of n, I can do it, just by going through n for-loops. For example, if n is 3, I can simply do:
result = []
for i in range(maxSum + 1):
for j in range(maxSum + 1 - i):
for k in range(maxSum + 1 - i - j):
tuple = [i, j, k]
result.insert(len(result), tuple)
return result
But in the above example, I have typed the three for-loops by hand. That is not what I want. I want to be able to make a function that works for any n, that is, a function tupleGenerator(maxSum, n) that generates all such n-tuples. The problem is, I am unable to change the number of for-loops in the function based on the input n.
Sorry don't have enough rep yet to comment, but here's a solution from math stackexchange
https://math.stackexchange.com/questions/2410399/how-to-find-all-the-n-tuples-with-nonnegative-integers-that-add-up-to-a-fixed-in
In particular Ocean Wong's answer, which includes a recursive Python solution (last answer on the page).
EDIT: slightly revised answer to include code as OP requested.
def stars_and_bars(num_objects_remaining, num_bins_remaining, filled_bins=()):
"""
The Stars and Bars (https://en.wikipedia.org/wiki/Stars_and_bars_(combinatorics)) problem can be thought of as
1. Putting m-1 bars ("|") in amongst a row of n stars
OR
2. Putting n balls into m bins.
This program lists all the possible combinations by doing so.
"""
if num_bins_remaining > 1:
# case 1: more than one bins left
novel_arrangement = [] # receptacle to contain newly generated arrangements.
for num_distributed_to_the_next_bin in range(0, num_objects_remaining + 1):
# try putting in anything between 0 to num_objects_remaining of objects into the next bin.
novel_arrangement.extend(
stars_and_bars(
num_objects_remaining - num_distributed_to_the_next_bin,
num_bins_remaining - 1,
filled_bins=filled_bins + (num_distributed_to_the_next_bin,),
)
# one or multiple tuple enclosed in a list
)
return novel_arrangement
else:
# case 2: reached last bin. terminate recursion.
# return a single tuple enclosed in a list.
return [
filled_bins + (num_objects_remaining,),
]
result = []
n = 3
for i in range(maxSum + 1):
result.extend(stars_and_bars(i, n))
print(result)
Python provides the itertools module that you can leverage for this:
maxSum, n = 2, 3
p1 = it.combinations_with_replacement(range(n), n)
p2 = filter( lambda m: sum(m) <= maxSum, p1 )
p3 = it.chain.from_iterable(it.permutations(p) for p in p2)
p4 = list(set(list(p3)))
sorted(p4)
This should be much easier on the memory consumption. You should print each step (for example print(list(p1))) to understand what each step is doing. That is easier to understand than anything that I will write in text here.

Using output of a function as an input in a different function

I'm trying to create a function in python (without numpy) that would imitate matrix multiplication in numpy. The program contains 2 functions. First function takes in 2 lists (l1 and l2) as input and creates a dummy list (dummy). The second function does the matrix multiplication of the lists l1 and l2 and inputs the values in the dummy list (dummy). The issue is that in the final output, the column values are being added and repeated in each row. However, if I hard code the dummy list in the program, it is giving correct output. If I run the first function to create dummy list separately, I'm getting correct output. Not sure where I'm going wrong. Providing both the codes below. Please help.
#Following code is giving me erroneous result:
l1 = [[1,2],[3,4],[5,6]]
l2 = [[7,8,0],[9,10,5]]
def dummy_matrix(l1,l2):
g = len(l1)
h = len(l2[0])
m = []
p = []
for j in range(h):
p.append(0)
for i in range(g):
m.append(p)
dummy = m
return(dummy)
def mat_mul(l1,l2):
f = dummy_matrix(l1,l2)
for a in range(len(l1)):
for b in range(len(l2[0])):
for c in range(len(l2)):
f[a][b] += l1[a][c]*l2[c][b]
return(f)
mat_mul(l1,l2)
#Following code has hard coded dummy list and is giving correct output
l1 = [[1,2],[3,4],[5,6]]
l2 = [[7,8,0],[9,10,5]]
def dummy_matrix(l1,l2):
g = len(l1)
h = len(l2[0])
m = []
p = []
for j in range(h):
p.append(0)
for i in range(g):
m.append(p)
dummy = m
return(dummy)
def matrix_multi(l1,l2):
f = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
for a in range(len(l1)):
for b in range(len(l2[0])):
for c in range(len(l2)):
f[a][b] += l1[a][c]*l2[c][b]
return(f)
matrix_multi(l1,l2)
You create your dummy_matrix wrong. You first create a row called p, append some zeros to it and then you append the same row multiple times.
dm = dummy_matrix(l1, l2)
dm[1][2] = 1
print(dm)
You can notice that this will modify multiple rows, showing that they are in fact the same reference.
You need to create fresh list for each row:
m = []
for i in range(g):
p = []
for j in range(h):
p.append(0)
m.append(p)

Python get the p-value of the array

My task is that when the input is *X, every input is an array of one column with n rows, but they may have different rows(eg X[0] is an array with 1 column and 10 rows, and X[2] is with 1 column and 9 rows), I want the code counts the p-value of the every two arrays and get the lowest p-value and the order of X[n](eg. X[1] means the first array and so on). The code goes wrong, 'local variable ans_1 referred before assignment'. I don't know how to do with this.
def mass_independent_ttest(*X):
min_pvalue = 10
for i in range(0, len(X)):
for j in range(i+1, len(X)):
df_1 = pd.DataFrame(X[i])
df_2 = pd.DataFrame(X[j])
df_first = df_1.loc[:,0]
df_second = df_2.loc[:,0]
temp = scipy.stats.ttest_ind(df_first, df_second)
temp_pvalue = temp.pvalue
if temp_pvalue < min_pvalue:
min_pvalue = temp_pvalue
ans_1 = i
ans_2 = j
ans_tuple = (ans_1, ans_2, min_pvalue)
return ans_tuple
`
At the last iteration of i, range(i+1, len(X)) will be an empty list, so that code won't execute, and ans_1 and ans_2 don't exist when you call ans_tuple = (ans_1, ans_2, min_pvalue). So you should evaluate your outer and inner loops to see if you are getting the expected number of iterations.
This example shows conceptually what is happening.
for i in range(0, len(X)):
print(list(range(i+1, len(X))))
=== Output: ===
[1, 2, 3, 4]
[2, 3, 4]
[3, 4]
[4]
[]

Replacing one number with another in PYTHON

I have declared a board array which is 10*10.I am reading the elements of the board which are 0, 1, and 2. After reading my board looks somewhat like this (shorter version 4*4)
0 1 0 2
2 1 0 1
0 2 1 0
1 2 1 0
Code:
board = []
for i in xrange(0, 10)
board.append(raw_input())
now i want to change all occurences of 0 to 1. I am not able to change it..what should i do..please write the modified code..(getting error as immutable)
Thanks for the answer it got changed.I should first covert the list to string then use replace function
As I understood, you have a list and just want to replace all 0's with 1's right? If it's like that, you can try to convert that list to string and use the replace method. Like: board = str(board) and then board = board.replace('0','1'). And then convert back to list with eval built-in function. But this may be too slow for big lists .
UPDATE >> If you do not want to use strings you can also code this:
If it is a 2d list like: L = [[1, 1, 0], [0, 2, 1], [0, 0, 0]] then:
for x in L:
for y in x:
if y == 0:
x[x.index(y)] = 1
And if it is just a common list like L = [1, 0, 2, 1, 0, 1] then:
for x in L:
if x == 0:
L[L.index(x)] = 1
for i in xrange(10):
for j in xrange(10):
if board[i][j] == 0:
board[i][j] = 1
This should works. If not, please show me how you create your board table.

Categories