String to n*n matrix in python - python

I am an undergraduate student who loves programming. I encountered a problem today and I don't know how to solve this problem.
I looked for "Python - string to matrix representation" (Python - string to matrix representation) for help, but I am still confused about this problem.
The problem is in the following:
Given a string of whitespace separated numbers, create an nxn matrix (a 2d list where with the same number of columns as rows)and return it. The string will contain a perfect square number of integers. The int() and split() functions may be useful.
Example:
Input: '1 2 3 4 5 6 7 8 9'
Output: [[1,2,3],[4,5,6],[7,8,9]]
Example 2:
Input: '1'
Output: [[1]]
My answer:
import numpy as np
def string_to_matrix(str_in):
str_in_split = str_in.split()
answer = []
for element in str_in_split:
newarray = []
for number in element.split():
newarray.append(int(number))
answer.append(newarray)
print (answer)
The test results are in the following:
Traceback (most recent call last):
File "/grade/run/test.py", line 20, in test_whitespace
self.assertEqual(string_to_matrix('1 2 3 4'), [[1,2],[3,4]])
AssertionError: None != [[1, 2], [3, 4]]
Stdout:
[[4]]
as well as
Traceback (most recent call last):
File "/grade/run/test.py", line 15, in test_small
self.assertEqual(string_to_matrix('1 2 3 4'), [[1,2],[3,4]])
AssertionError: None != [[1, 2], [3, 4]]
Stdout:
[[4]]
as well as
Traceback (most recent call last):
File "/grade/run/test.py", line 10, in test_one
self.assertEqual(string_to_matrix('1'), [[1]])
AssertionError: None != [[1]]
Stdout:
[[1]]
as well as
Traceback (most recent call last):
File "/grade/run/test.py", line 25, in test_larger
self.assertEqual(string_to_matrix('4 3 2 1 8 7 6 5 12 11 10 9 16 15 14 13'), [[4,3,2,1], [8,7,6,5], [12,11,10,9], [16,15,14,13]])
AssertionError: None != [[4, 3, 2, 1], [8, 7, 6, 5], [12, 11, 10, 9], [16, 15, 14, 13]]
Stdout:
[[13]]
I am still confused how to solve this problem. Thank you very much for your help!

Assuming you don't want numpy and want to use a list of lists:
def string_to_matrix(str_in):
nums = str_in.split()
n = int(len(nums) ** 0.5)
return list(map(list, zip(*[map(int, nums)] * n)))
nums = str_in.split() splits by any whitespace, n is the side length of the result, map(int, nums) converts the numbers to integers (from strings), zip(*[map(int, nums)] * n) groups the numbers in groups of n, list(map(list, zip(*[map(int, nums)] * n))) converts the tuples produced by zip into lists.

Assuming you want to make this dynamic.
str_in = '1 2 3 4 5 6 7 8 9'
a = str_in.split(" ")
r_shape = int(math.sqrt(len(a)))
np.array([int(x) for x in a]).reshape(r_shape, r_shape)

Use split, create the 1D numpy array, then use reshape:
>>> s = '1 2 3 4 5 6 7 8 9'
>>> np.array([s.split(), dtype=int).reshape(3,3)
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
If you don't know the size of the array, but you know it's square (same width / height), then you can use math.sqrt to get the inputs for reshape:
>>> import math
>>> s = '1 2 3 4 5 6 7 8 9'
>>> arr = np.array(s.split(), dtype=int)
>>> size = int(math.sqrt(len(arr)))
>>> arr.reshape(size, size)
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])

Given that you will always get perfect square number of ints:
import numpy as np
input_strings = '1 2 3 4 5 6 7 8 9'
arr = np.array(input_strings.split(), dtype=int)
n = int(len(arr) ** 0.5)
arr.reshape(n, n)
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
Note: in your case, str.split is better off without explicit sep in order to work fine with multiple whitespaces in between the digits.

import numpy as np
def string_to_matrix(str_in):
str_in_split = str_in.split()
numbers = list(map(int, str_in_split))
size = r_shape = int(np.sqrt(len(numbers)))
return np.array(numbers).reshape(r_shape, r_shape)
This is why you always got: AssertionError: None != ...
assertEqual(A, string_to_matrix("...")) verifies if A is equals to the value returned by string_to_matrix. In your code you don't return anything so it is None
The other issue is how you splitted the string, the easier options is to split everything and convert to number, and then reshape to sqrt(number of elements). This assumes that input length can be splited to form a nxn matrix

import math
string = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16"
stringItems = string.split(" ")
numberOfItems = len(stringItems)
if math.sqrt(numberOfItems) - int(math.sqrt(numberOfItems)) == 0:
width = int(math.sqrt(numberOfItems))
array = []
finalArray = []
for i in range (0, width):
for j in range (0, width):
array.insert(j, stringItems[0])
stringItems.pop(0)
finalArray.insert(i, array)
array = []
print finalArray
else:
print "I require a string with length equal to a square number please"

Related

How can i do the transpose of a matrix in python? [duplicate]

This question already has answers here:
Basic matrix transpose in python
(5 answers)
Closed 6 months ago.
I am making a function in python in which when taking a matrix A, it returns a matrix B with swapped rows and columns, example:
if i enter this matrix:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
Should return
1 5 9 13
2 6 10 14
3 7 11 15
4 8 12 16
but what I get is:
array([[ 1, 5, 9, 13],
[ 5, 6, 10, 14],
[ 9, 10, 11, 15],
[13, 14, 15, 16]])
I don't understand why, could someone help me understand this error and how can I solve it?
my code:
def transpose(matrix):
for i in range(matrix.shape[0]):
for j in range(matrix.shape[1]):
matrix[i][j] = matrix[j][i]
return matrix
(I can't use default functions like transpose, I have to code)
This line
matrix[i][j] = matrix[j][i]
is your issue.
For example, when i = 1 and j = 2, you set matrix[1][2] to 10 because matrix[2][1] is 10. When you come around the next time to i = 2 and j = 1, you set matrix[2][1] to 10 because matrix[1][2] was set to 10 even though it was originally 7, it doesn't keep a memory of the previous value.
Depending on if you want the function to mutate the original matrix or return a new matrix with changes values (but keep the original) will change how you create this function.
To mutate the original
def transpose(matrix):
matrix2 = numpy.copy(matrix)
for i in range(matrix.shape[0]):
for j in range(matrix.shape[1]):
matrix[i][j] = matrix2[j][i]
return matrix
To return a new array
def transpose(matrix):
matrix2 = numpy.copy(matrix)
for i in range(matrix.shape[0]):
for j in range(matrix.shape[1]):
matrix2[i][j] = matrix[j][i]
return matrix2
zip can do this for you. Unpack the list and pass sub lists as arguments to the zip:
lst = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16],
]
transposed = list(zip(*lst))
for i in transposed:
print(i)
output:
(1, 5, 9, 13)
(2, 6, 10, 14)
(3, 7, 11, 15)
(4, 8, 12, 16)
You can use numpy.transpose to transpose a matrix.
As for why your code is not working is because your program does the follow assignments in a loop:
matrix[0][2] = matrix[2][0] # writes 9
...
matrix[2][0] = matrix[0][2] # writes 9 instead of 3 because matrix[0][2] has previously been updated
So to fix this you can use an intermediate variable like output_matrix in this example:
def transpose(matrix):
output_matrix = np.zeros_like(matrix)
for i in range(matrix.shape[0]):
for j in range(matrix.shape[1]):
output_matrix[i][j] = matrix[j][i]
return output_matrix

Split a numpy array into 8-elements arrays and invert each of them

Well, I have a numpy array like that:
a=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]
My desired output is:
b=['87654321','161514131211109','2423222120191817']
For it, I need first to split "a" into arrays of 8 elements and then I have a list like that:
np.split(a) = [array([1, 2, 3, 4, 5, 6, 7, 8], dtype=int8),
array([9, 10, 11, 12, 13, 14, 15, 16], dtype=int8),
array([17, 18, 19, 20, 21, 22, 23, 24], dtype=int8)]
so, I need to invert each array into it and join the numbers to make like a list of joint numbers.
No need for numpy, though it will work for an array as well. One way:
>>> [''.join(str(c) for c in a[x:x+8][::-1]) for x in range(0, len(a), 8)]
['87654321', '161514131211109', '2423222120191817']
Try this. You reshape your data and then convert it to string elements. Loop it and append it to new list.
import numpy as np
a=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]
lst = list(np.array(a).reshape(3,8).astype("U"))
my_lst = []
for i in lst:
my_lst.append("".join(i[::-1]))
print(my_lst)
The simplest way is first to reverse the original array (or create a reversed copy), and then to split:
a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]
acopy = a[::-1]
splitted = np.array_split(acopy, 3)
print(splitted[0]) # [24 23 22 21 20 19 18 17]
print(splitted[1]) # [16 15 14 13 12 11 10 9]
print(splitted[2]) # [8 7 6 5 4 3 2 1]
Now when lists are reversed, you can join elements of each list to make strings:
str1 = ''.join(str(x) for x in splitted[0]) # '2423222120191817'
str2 = ''.join(str(x) for x in splitted[1]) # '161514131211109'
str3 = ''.join(str(x) for x in splitted[2]) # '87654321'

How can I sum every n array values and place the result into a new array? [duplicate]

This question already has answers here:
Sum slices of consecutive values in a NumPy array
(5 answers)
Closed 3 years ago.
I have a very long list of array numbers I would like to sum and place into a new array. For example the array:
[1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8]
would become:
[6,15,16,6,15,x]
if I was to sum every 3.
I cannot figure out how to go about it. I think possibly one problem is I do not know the length of my array - I do not mind losing the bottom bit of data if necessary.
I have tried the numpy.reshape function with no success:
x_ave = numpy.mean(x.reshape(-1,5), axis=1)
ret = umr_sum(arr, axis, dtype, out, keepdims)
I get an error:
TypeError: cannot perform reduce with flexible type
Cut the array to the correct length first then do a reshape.
import numpy as np
N = 3
a = np.array([1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8])
# first cut it so that lenght of a % N is zero
rest = a.shape[0]%N
a = a[:-rest]
assert a.shape[0]%N == 0
# do the reshape
a_RS = a.reshape(-1,N)
print(a_RS)
>> [[1 2 3]
[4 5 6]
[7 8 1]
[2 3 4]
[5 6 7]]
then you can simply add it up:
print(np.sum(a_RS,axis=1))
>> [ 6 15 16 9 18]
You can use a list comprehension do this:
ls = [1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8]
res = [sum(ls[i:i+3]) for i in range(0, len(ls), 3)]
[6, 15, 16, 9, 18, 8]
This will result in all the numbers being included in the resulting sum. If you don't want this to happen, then you can just check for it and replace the last sum with whatever value you want:
if (len(ls)%3) != 0:
res[-1] = 'x'
[6, 15, 16, 9, 18, 'x']
Or remove it entirely:
if (len(ls)%3) != 0:
res[:] = res[:-1]
[6, 15, 16, 9, 18]
Why don't you just simply use a list comprehension? E.g.
my_list = [1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8]
len_list = len(my_list) - len(my_list) % 3 # ignore end of list, s.t., only tuples of three are considered
[my_list[i] + my_list[i+1] + my_list[i+2] for i in range(0, len_list, 3)]

Python: TypeError: unsupported operand type(s) for -: 'list' and 'int'

I am writing a function delta that takes two arguments: a partitioning of a phone book and a list or tuple containing the distribution of the first letters of telephone subscriber's last names. The function must return the delta of the given partitioning of the phone book for the given distribution of the first letters of telephone subscriber's last names.
A B C D E F G H I J K L M N 0 P Q R S T U V W X Y Z
16 4 17 10 15 4 4 6 7 14 9 17 27 6 1 9 0 12 20 8 0 3 4 0 3 4
For example: in total there are 220 names and the telephone company has decided to print 4 volumes. Ideally, each of these volumes should thus contain 220 / 4 = 55 names. One possible partitioning is A-D E-J K-O P-Z with counts of 47, 50, 60 and 63 names. In absolute value these counts deviate 8, 5, 5 and 8 names from the ideal 55 names per volume. We refer to the total sum of these deviations as the delta of the partitioning of the phone book. For this partitioning, the delta is thus equal to 26.
I have the following error in my code:
TypeError: unsupported operand type(s) for -: 'list' and 'int'
Anybody knows what I am doing wrong? The error appears to be in the last lines of the last function delta(). I also tried by making an integer of the elements of the list or a string of the list but it is still not working.
def counts(seq):
'''
>>> counts('A-D E-J K-O P-Z')
(4, 6, 5, 11)
>>> counts('A-G H-O P Q-Z')
(7, 8, 1, 10)
>>> counts('A-D E-K L-P Q-Z')
(4, 7, 5, 10)
>>> counts('A-D F-K L-P Q-Z')
Traceback (most recent call last):
AssertionError: invalid partitioning
'''
r = str(seq)
input_string = r.split(' ')
q = []
for dletter in input_string:
if '-' in dletter:
q.append(ord(dletter[2]) - ord(dletter[0]) + 1)
else:
q.append(1)
assert sum([x for x in q]) == 26, "invalid partitioning"
chars = "abcdefghijklmnopqrstuvwxyz"
chars = chars.upper()
for char in chars:
count = r.count(char)
assert count == 1, "invalid partitioning"
return (tuple(q))
def delta(seq, names):
'''
>>> names = (16, 4, 17, 10, 15, 4, 4, 6, 7, 14, 9, 17, 27, 6, 1, 9, 0, 12, 20, 8, 0, 3, 4, 0, 3, 4)
>>> delta('A-D E-J K-O P-Z', names)
26.0
>>> delta((7, 8, 1, 10), names)
94.0
>>> delta('A-D E-K L-P Q-Z', names)
18.0
>>> delta(42, names)
Traceback (most recent call last):
AssertionError: invalid partitioning
'''
r = counts(seq)
import itertools
q = list(itertools.accumulate(r))
j = list()
for i in q:
f = sum(names[:i])
j.append(f)
s = [t - s for s, t in zip(j, j[1:])]
d = [j[:1]]
k = d + s
g = list(abs(x - 55) for x in k)
n = float(sum(g))
return n
Change d = [j[:1]] to d = j[:1].
g = list(abs(x - 55) for x in k) variable x is a list because of d = [j[:1]].

Python Array Addition recursion

So I was doing coderbyte's challenge and I have problems with one:
ArrayAdditionI, here's the statement of the problem:
'''
Using the Python language, have the function ArrayAdditionI(arr) take the array of numbers stored in arr
and return the string true if any combination of numbers in the array can be added up to equal the largest number in the array,
otherwise return the string false.
For example: if arr contains [4, 6, 23, 10, 1, 3] the output should return true because 4 + 6 + 10 + 3 = 23.
The array will not be empty, will not contain all the same elements, and may contain negative numbers.
'''
Since I couldn't do it, I researched for a solution and I found this:
def countFor(arr, m, s0):
if len(arr) == 0:
return False
a0 = arr[0]
ar = arr[1:]
sw = s0 + a0
if sw == m:
return True
if countFor(ar, m, sw):
return True
if countFor(ar, m, s0):
return True
return False
def ArrayAdditionI(arr):
m = max(arr)
arr.remove(m)
return str(countFor(arr, m, 0)).lower()
Now, I'm trying to understand what exactly the code does on every loop, I printed out the output for every loop of this list [4, 6, 23, 10, 1, 3]:
Input: [4, 6, 10, 1, 3] 23 0
a0: 4
ar: [6, 10, 1, 3]
sw: 4
Input: [6, 10, 1, 3] 23 4
a0: 6
ar: [10, 1, 3]
sw: 10
Input: [10, 1, 3] 23 10
a0: 10
ar: [1, 3]
sw: 20
Input: [1, 3] 23 20
a0: 1
ar: [3]
sw: 21
Input: [3] 23 21
a0: 3
ar: []
sw: 24
Input: [] 23 24
Input: [] 23 21
Input: [3] 23 20
a0: 3
ar: []
sw: 23
True
and I follow and understand what's going on, until the last three loops, I don't what part of the code makes it go from "Input: [] 23 24" to "Input : [] 23 21" to "Input: [3] 23 20".
Alright - here are the calls. Child calls are indented with respect to their parents:
Call countFor([4, 6, 10, 1, 3], 23, 0)
Call countFor([6, 10, 1, 3], 23, 4) from the first if
Call countFor([10, 1, 3], 23, 10) from the first if
Call countFor([1, 3], 23, 20) from the first if
Call countFor([3], 23, 21) from the first if
Call countFor([], 23, 24) from the first if
Call countFor([], 23, 21) from the second if
Call countFor([3], 23, 20) from the second if
Key point is that the second recursive call in countFor is not in an elif - it is an if in its own right, so after we come back up the call-stack, the second recursive call can also happen.
You haven't traced all of the logic, just the input and update at the top of the routine.
At [] 23 24, let's follow the logic:
if sw == m:
Nope ... that's 24 vs 23 ...
if countFor(ar, m, sw):
This produces your [] 23 24 line.
Since the array has 0 elements, the call immediately returns False.
if countFor(ar, m, s0):
This produces your [] 23 21 line. Again, the empty array gets an immediate False.
We fall one more line and return a False to the previous call.
The call that produced this one was the first countFor, calling with
if countFor([3], 23, 21):
where that 21 is the value of sw. We drop to the second call, the one with s0. At this point, s0 is 20, so the call looks like:
if countFor([3], 23, 20):
... and this call sees that 20+3 = 23 = m, so it returns True.
Does that clarify things for you?
just use the package itertools.combinations:
from itertools import combinations
def arrayChallenge(numbers):
expected_sum = max(numbers)
numbers.remove(expected_sum)
result = [seq for i in range(len(numbers), 0, -1)
for seq in combinations(numbers, i)
if sum(seq) == expected_sum]
return len(result) > 0
print(arrayChallenge([4, 6, 23, 10, 1, 3]))

Categories

Resources