Error in converting an array to 2D matrix in Python - python

I have the problem regarding the output of this algorithm. For example: for input chunk([1, 2, 3, 4, 5, 6, 7, 8], 3) it should return [[ 1, 2, 3], [4, 5, 6], [7, 8, '']] but instead it returns [[7, 8, 6], [7, 8, 6], [7, 8, 6]].
However, when m_list is defined under the loop for r in range(rows):, it returns correct value.
I can't figure out why it returns wrong value if m_list is defined outside the loop for r in range(rows):. What could be the reason ?
# --- Directions
# Given an array and chunk size, divide the array into many subarrays
# where each subarray is of length size
# --- Examples
# chunk([1, 2, 3, 4], 2) --> [[ 1, 2], [3, 4]]
# chunk([1, 2, 3, 4, 5], 2) --> [[ 1, 2], [3, 4], [5, '']]
# chunk([1, 2, 3, 4, 5, 6, 7], 3) --> [[ 1, 2, 3], [4, 5, 6], [7, '', '']]
import math
def chunk (array, size):
rows = 0
l = len(array)
if l % size == 0:
rows = l/size
else:
rows = int(math.floor(l/size) + 1)
m_list = ['' for e in range(size)]
m_matrix = [['' for g in range(size)] for w in range(rows)]
i = 0
for r in range(rows):
for u in range(size):
if i == l:
break
else:
m_list[u] = array[i]
i += 1
m_matrix[r] = m_list
return m_matrix
length = int(raw_input('how many elements you want in the array?: '))
m_inputArray = ['' for q in range(length)]
print 'Debug0:--> ' + str(m_inputArray)
for z in range(length):
p = int(raw_input('Enter the value at index %i: ' %(z)))
m_inputArray[z] = p
m_inputSize = int(raw_input('Enter the size: '))
result = chunk(m_inputArray, m_inputSize)
print result

There are several things wrong with your code. Firstly every loop of u the start value of m_list is the previous list (so the first time it is ['','',''] but the second time it is [1,2,3], and the third time it is [4,5,6]. Which means that since the third time only one value is left in the array, only the first value in the m_list gets redefined, resulting in an m_list of [7,5,6].
Secondly, by saying: m_matrix[u] = m_list you are creating a reference to m_list, you are not copying m_list into m_matrix. This means that once m_list changes, so do the values in m_matrix. Which means in the end you will have defined m_matrix to be [m_list,m_list,m_list], resulting in your results of [[7,5,6],[7,5,6],[7,5,6]]. A solution for this would be to make slice of m_list, like this: m_matrix = m_list[:].
This is how I would do the whole thing:
def chunk(inputarray,size):
array = inputarray[:]
m_matrix = []
while len(array) > 0:
if len(array[:size]) < size:
array.extend(['' for j in range(size-len(array[:size]))])
m_matrix.append(array[:size])
del array[:size]
return m_matrix
If you don't need the original array anymore you can also remove the array = inputarray[:] line of code. Also, probably not the fastest/best way of doing this, but I just wanted to provide something quick. This was done in python 2.7, so if you're using another version you might have to alter some things.

seems a bit over complicated. this is what i came up with.
written for python 3 but does work in 2.
def pop_with_replace(array, index=0, blank=''):
try:
return array.pop(index)
except IndexError:
return blank
def chunk(array, size):
out = []
while array:
t_list = []
for i in range(size):
t_list.append(pop_with_replace(array))
out.append(t_list)
return out
if __name__ == '__main__':
print(chunk(list(range(10)), 3))
there's some things we could change as well. like removing this method pop_with_replace for a ternary operator? i didn't put this in the first solution as they can be awkward to read if not used to them.
t_list.append(array.pop() if array else '')
looking at this we could roll it all up into a list comp. but we're starting to get hard to read.
While array:
out.append([array.pop(0) if array else '' for x in range(size)]
but it does leave the final code looking nice and small.
def chunk(array, size):
out = []
while array:
out.append([array.pop(0) if array else '' for x in range(size)])
return out

In this example there is only one m_list where you update values and final result is [m_list, m_list, m_list ... m_list].
If you define m_list in loop new list will be created in each loop pass.
You can assign directly to m_matrix[r][u] = array[i]
Note that you are with list of lists, not true matrix, and m_matrix[r] = m_list replaces list on r-th position with reference to m_list list.

Related

how to fill matrix using range without numpy?

I created a matrix of zeros using lists, and I want to fill it based on matrix size, but I want the numbers to come sequentially.
I tried the following
matrix = []
for i in range(3):
a =[]
for j in range(3):
a.append(i+j)
matrix.append(a)
I get this:
[[0, 1, 2], [1, 2, 3], [2, 3, 4]]
but the expected is:
[[0, 1, 2], [3, 4, 5], [6, 7, 8]]
thanks
Have your outer range loop with a step to provide the base value for each level. In this case, just change:
for i in range(3):
to:
for i in range(0, 9, 3):
It might be slightly more readable to phrase it in terms of a named variable like dim (for "dimension"):
dim = 3
for i in range(0, dim ** 2, dim):
a = []
for j in range(dim):
a.append(i+j)
matrix.append(a)
Tagging on to #ShadowRanger's answer, rather than appending you can use a list comprehension if you would like.
dim = 3
matrix = [list(range(i, i+dim)) for i in range(0, dim**2, dim)]
You could multiply i by 3 like so:
matrix = []
for i in range(3):
a =[]
for j in range(3):
a.append(3*i + j) <-----
matrix.append(a)

How to store indeces of the respective numbers in a list in seperate array using Python

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]

Python List control flow - why won't skip elements already in list

Essentially trying to add numbers to list L based on a pattern.
starting at index point 0 you print the element of that index point. The next index point then becomes becomes the int of the element you just printed and the pattern continues until done.
The catch is if that index point has already been used you move one to the left until you reach an index point that has not been used.
Below is my solution to the problem. Everything seems to work i.e. it moves along the number as it is suppose to however when it encounters an index point that it has already used it still prints that element.
Any ideas why it doesn't appear to be skipping to the left properly?
Output is:
If L is: L = [1, 4, 4, 1, 2, 4, 3]
N is: 1, 4, 2, 4, 2, 4, 2] when it should
[1, 4, 2, 4, 1, 4, 3]
# other way around
L = [1, 4, 4, 1, 2, 4, 3]
for index, s in enumerate(L):
print(index, s)
print(' ', L)
M = []
N = []
T = []
i = L[0]
index_position = 0
while len(T) != len(L):
if index_position in T:
index_position = index_position + 1
else:
N.append(i)
T.append(index_position)
index_position = i
i = L[index_position]
print('N is: ', N)
print('T is: ', T)
seen_that_before = []
N = []
for number in L
if number in seen_that_before: continue
seen_that_before.append(number)
N.append(number)
Something like that?
Please use significant variable names. N, T, L or i are confusing.

Numbers in a Matrix

I tried to solve the following problem with Python:
But I got stuck at generating a single valid table. I was expecting the program to display a valid matrix, but in order for the program to continue and not print None, I had to assign a 7 for a square that has no possibles. What should be fixed?
My code so far:
from pprint import pprint
import sys
import random
sys.setrecursionlimit(10000)
def getPossiblesForSquare(sqx,sqy,matrix):
'''Gets the possible entries of matrix[sqy][sqx].
Assumes it equals 0.'''
assert matrix[sqy][sqx]==0
# get the row that it is on
rowon=matrix[sqy]
# columns are a little trickier
colon=[matrix[row][sqx] for row in range(5)]
# find the possibilities!
possibles=list(range(1,7))
for item in list(set(rowon+colon)): # remove duplicates
if not (item == 0) and (item in possibles):
del possibles[possibles.index(item)]
random.shuffle(possibles)
return possibles
def getPossiblesForMatrix(matrix):
'''Gets all the possible squares for a matrix.'''
possiblesdict={}
for y in range(6):
for x in range(6):
if matrix[y][x]==0:
possiblesdict[(y,x)]=getPossiblesForSquare(x,y,MATRIX)
return possiblesdict
def flattenList(matrix):
result=[]
for i in matrix:
if not isinstance(i,list):
result+=[i]
else:
result+=flattenList(i)
return result
def getPossibleMatrix(startMatrix, iteration=0, yon=1, prevZeroInd=None):
if 0 not in flattenList(startMatrix):
print('RESULT:\n\n')
return startMatrix
else:
# find&fill in the first blank one
ind=flattenList(startMatrix).index(0)
y=ind//6
x=ind%6
if (x,y)==prevZeroInd:
startMatrix[y][x]=7
else:
possibles=getPossiblesForSquare(x,y,startMatrix)
if len(possibles)==0:
startMatrix[y][x]=7
else:
startMatrix[y][x]=possibles[0]
if iteration <= 6:
return getPossibleMatrix(startMatrix, iteration+1, yon, (x,y)) # <<BUG
else:
if yon!=4:
return getPossibleMatrix(startMatrix, 0, yon+1, (x,y))
MATRIX=[[1,2,3,4,5,6],
[2,0,0,0,0,5],
[3,0,0,0,0,4],
[4,0,0,0,0,3],
[5,0,0,0,0,2],
[6,5,4,3,2,1]]
result=getPossibleMatrix(MATRIX)
pprint(result)
Why your script hangs:
Essentially your script encounters problems here:
for item in list(set(rowon + colon)): # remove duplicates
if not (item == 0) and (item in possibles):
del possibles[possibles.index(item)]
At the third iteration, for the third cell your if condition is evaluated as true for all possible values [1 to 6] (if you output the matrix you will see that the set() you are creating contains all elements), so you always return zero, re-check the values, return zero ad infinitum.
If you're looking to brute-force a solution out of this, you might want to update the sqx and sqy to go to a different cell when possibles is empty.
Another additional small mistake I located was:
# you are checking values 1-5 and not 1-6!
possibles = list(range(1, 6)) # should be range(7) [exclusive range]
Don't forget that range is exclusive, it doesn't include (excludes) the upper limit.
There exist of course, different ways to tackle this problem.
A possible -alternate- solution:
Read this for the general, alternate view of how to solve this. If you do not want to see a possible solution, skip the 'code' part.
The solution matrix (one of the possible ones) has this form (unless I am making a horrible mistake):
MATRIX = [[1, 2, 3, 4, 5, 6],
[2, 3, 6, 1, 4, 5],
[3, 1, 5, 2, 6, 4],
[4, 6, 2, 5, 1, 3],
[5, 4, 1, 6, 3, 2],
[6, 5, 4, 3, 2, 1]]
The Logic is as follows:
You must observe the symmetry present in the matrix. Specifically, every row and every column displays a 'flip and reverse' symmetry. For example, the first and last rows are connected by this equation :
row[0] = REV(flip(row[n]))
Similarly, all additional rows (or columns) have their corresponding counterpart:
row[1] = REV(flip(row[n-1]))
and so on.
So, for n=6 this essentially boils down to finding the (n / 2) -1 (because we already know the first and last row!) and afterwards flipping them (not the finger), reversing them and assigning them to their corresponding rows.
In order to find these values we can observe the matrix as a combination of smaller matrices:
These make the first two (unknown) rows of the matrix:
sub_matrix = [[1, 2, 3, 4, 5, 6],
[2, 0, 0, 0, 0, 5],
[3, 0, 0, 0, 0, 4],
[6, 5, 4, 3, 2, 1]]
and the other two rows can be made by finding the correct values for these two.
Observe the restrictions in hand:
In column [1][1] and [1][m-1] we cannot:
place a 2 or a 5
In columns [1][2] and [1][m-2] we cannot:
place the previous values ([2, 5]) along with ([3, 4]) so, we cannot have a value in [2,3,4,5]
For the inner columns we're left with the set set(1-6) - set(2-5) = [1, 6]
and since we get a normal row and a single inverted and flipped row for this, we can arbitrarily select a value and add it as a column value.
By using another list we can keep track of the values used and fill out the rest of the cells.
Coding this: (Spoilers)
Note: I did not use numpy for this. You can and should though. (Also, Python 2.7)
Also, I did not use recursion for this (you can try to, by finding the same matrix for bigger values of n [I believe it's a good fit for a recursive function].
First, in order to not type this all the time, you can create a n x n matrix as follows: (This isn't much of a spoiler.)
# our matrix must be n x n with n even.
n = 6
# Create n x n matrix.
head = [i for i in xrange(1, n + 1)] # contains values from 1 to n.
zeros = [0 for i in xrange(1, n-1)] # zeros
tail = [i for i in xrange(n, 0, -1)] # contains values from n to 1.
# Add head and zeros until tail.
MATRIX = [([j] + zeros + [(n+1)-j]) if j != 1 else head for j in xrange(1, n)]
# Add tail
MATRIX.append(tail)
Then, create the smaller (n/2 + 1) x n array:
# Split matrix and add last row.
sub_matrix = MATRIX[:(n / 2)] + [tail]
Afterwards, a small function called sub = fill_rows(sub_matrix) comes in and takes care of business:
def fill_rows(mtrx):
# length of the sub array (= 4)
sub_n = len(mtrx)
# From 1 because 0 = head
# Until sub_n -1 because the sub_n - 1 is = tail (remember, range is exclusive)
for current_row in xrange(1, sub_n - 1):
print "Current row: " + str(current_row)
# -- it gets messy here --
# get values of inner columns and filter out the zeros (matrix[row][n / 2] == 0 evaluates to False)
col_vals_1 = [mtrx[row][n / 2] for row in xrange(0, sub_n) if mtrx[row][(n / 2)]]
col_vals_2 = [mtrx[row][(n / 2) - 1] for row in xrange(0, sub_n) if mtrx[row][(n / 2) - 1]]
col_vals = col_vals_1 + col_vals_2
# print "Column Values = " + str(col_vals)
row_vals = [mtrx[current_row][col] for col in xrange(0, n) if mtrx[current_row][col]]
# print "Row Values = " + str(row_vals)
# Find the possible values by getting the difference of the joined set of column + row values
# with the range from (1 - 6).
possible_values = list(set(xrange(1, n + 1)) - set(row_vals + col_vals))
print "Possible acceptable values: " + str(possible_values)
# Add values to matrix (pop to remove them)
# After removing add to the list of row_values in order to check for the other columns.
mtrx[current_row][(n-1)/2] = possible_values.pop()
row_vals.append(mtrx[current_row][(n - 1) / 2])
mtrx[current_row][(n-1)/2 + 1] = possible_values.pop()
row_vals.append(mtrx[current_row][(n-1) / 2 + 1])
# New possible values for remaining columns of the current row.
possible_values = list(set(xrange(1, n + 1)) - set(row_vals))
print "Possible acceptable values: " + str(possible_values)
# Add values to the cells.
mtrx[current_row][(n - 2)] = possible_values.pop()
mtrx[current_row][1] = possible_values.pop()
# return updated sub-matrix.
return mtrx
The only thing left to do now is take those two rows, flip them, reverse them and add the head and tail to them:
print '=' * 30 + " Out " + "=" * 30
# Remove first and last rows.
del sub[0]
sub.pop()
# reverse values in lists
temp_sub = [l[::-1] for l in sub]
# reverse lists in matrix.
temp_sub.reverse()
# Add them and Print.
pprint([head] + sub + temp_sub + [tail])
This outputs what, I hope, is the right matrix:
============================== Out ==============================
[[1, 2, 3, 4, 5, 6],
[2, 3, 6, 1, 4, 5],
[3, 1, 5, 2, 6, 4],
[4, 6, 2, 5, 1, 3],
[5, 4, 1, 6, 3, 2],
[6, 5, 4, 3, 2, 1]]
Additionally
By using this way of solving it the answer to the problem in hand becomes more easy. Viewing the matrix as a combination of these sub-matrices you can tell how many of these combinations might be possible.
As a closing note, it would be a good work-out to modify it a bit in order to allow it to find this array for an arbitrary (but even) number of n.
You have infinite recursion. Your first three iterations are fine: your second row adds one possibility at a time, turning from 200005 into 214305. At this point, you find that there are no possible choices. You overwrite the existing 0 with a new 0, and then fail to backtrack. Each of these is an error: 6 is a possible value, and you have no recovery code.
Here is the alteration I made to track the problem; additions are in double-star containers. When you have a sick program, learn how to ask where it hurts. The print function is an excellent instrument.
def getPossibleMatrix(startMatrix, **iter=0**):
if 0 not in flattenList(startMatrix):
return startMatrix
else:
# find&fill in the first blank one
ind=flattenList(startMatrix).index(0)
y=ind//6
x=ind%6
possibles=getPossiblesForSquare(x,y,startMatrix)
if len(possibles)==0:
startMatrix[y][x]=0
**print ("No possibles; current location remains 0")**
else:
startMatrix[y][x]=possibles[0]
****print ("Added first possible")
print (startMatrix)
if iter <= 6:**
return getPossibleMatrix(startMatrix, **iter+1**) # <<BUG

QuickSort is returning correct values, but not sorting in place

I'm struggling to understand why my QuickSort returns the sorted values correctly, but the resulting array is not sorted correctly.
def qSort(array):
n = len(array)
if (n == 1 or n ==0):
return array
p_index = partition(array)
p_value = array[p_index]
return(qSort(array[0:p_index]) + [p_value] + qSort(array[p_index+1:n]))
def partition(array):
pivot = array[0]
i = 1
for j in xrange(1,len(array)):
print j
if array[j] < pivot:
tmp = array[j]
array[j] = array[i]
array[i]=tmp
i += 1
tmp = array[i-1]
array[i-1] = pivot
array[0] = tmp
return i-1
Here is some sample output:
>>> q = [5,4,3,2,1]
>>> qSort(q)
[1, 2, 3, 4, 5]
>>> q
[1, 4, 3, 2, 5]
Thank you in advance!
In Python, slicing and combining lists create new lists. If you want your recursive calls to operate on a single list in place, pass the list and the bounds into the call, and don't return anything from the function. Something like:
def qsort(array, low, high):
if high-low < 2:
return
# Choose pivot, do partition within bounds
if partition > low:
qsort(array, low, partition)
if partition < high:
qsort(array, partition+1, high)
Then just call qsort(a, 0, len(a)) to sort the array.
This is because you are making up a new list in your return statement.
return(qSort(array[0:p_index]) + [p_value] + qSort(array[p_index+1:n]))
If the qSort function reaches a base case, it returns a list, which is concatenated with [p_value] and returned as a list. You do not make changes to the passed in list anywhere.
When you call your qSort function recursively, you are giving it a slice of the list and the function returns the list in the base case which you then append to the pivot and the other recursive call, hence generating a new list.
See what is happening by changing your qSort function to
def qSort(array):
n = len(array)
if (n == 1 or n ==0):
return array
p_index, array = partition(array)
p_value = array[p_index]
returnVal = qSort(array[0:p_index]) + [p_value] + qSort(array[p_index+1:n])
print "Returning:", returnVal, "Original Array:", array
return returnVal
Output -
>>> q = [5,4,3,2,1]
>>> qSort(q)
Returning: [2, 3] Original Array: [2, 3]
Returning: [2, 3, 4] Original Array: [2, 3, 4]
Returning: [1, 2, 3, 4] Original Array: [1, 4, 3, 2]
Returning: [1, 2, 3, 4, 5] Original Array: [1, 4, 3, 2, 5]
[1, 2, 3, 4, 5]
To reflect the changes in your original list, you have the option of doing q = qSort(q).
P.S - Setting up a random index instead of the first value would be better for your quicksort function. See the bit here on Choice of Pivots.
apply the function back to q
q = qSort(q)
If you want to return the array and also sort in place you should before returning make the array equal to the result and not make a new one. You can do that by changing your return statement to:
array[:] = qSort(array[0:p_index]) + [p_value] + qSort(array[p_index+1:n])
return array
Note that
array = qSort(array[0:p_index]) + [p_value] + qSort(array[p_index+1:n])
does not work either, because the lhs variable will be treated as a local variable.

Categories

Resources