Convert string with hard coded line breaks into matrix in python - python

I am trying to create a class that takes a string of digits with hard coded line breaks and outputs a matrix and details about that matrix. In the first instance i just want to be able to create the matrix but I am struggling. I'm aware that I could probably do this very easily with numpy or something similar but trying to practice.
class Matrix:
def __init__(self, matrix_string):
self.convert_to_list = [int(s) for s in str.split(matrix_string) if s.isdigit()]
self.split = matrix_string.splitlines()
I think i want to combine the two things I have already done but I cant figure out how to apply my convert_to_list method to every element in my split method.
Getting very confused.
SAMPLE INPUT/OUTPUT
Input = " 1 8 7 /n 6 18 2 /n 1 9 7 "
Desired Output = [[1, 8, 7], [6, 18, 2], [1, 9, 7]]

It looks like you want a list of lists. For that you can use nested list comprehension.
s = " 1 8 7 /n 6 18 2 /n 1 9 7 "
lst = [[int(x) for x in r.split()] for r in s.split('/n')]
print(lst)
Output
[[1, 8, 7], [6, 18, 2], [1, 9, 7]]

It's not that hard actually:
s = " 1 8 7 /n 6 18 2 /n 1 9 7 "
print([i.split() for i in s.split('/n')])
easier way but longer:
s = s.split('/n')
new = []
for i in s:
new.append(i.split())
print(new)
output:
[['1', '8', '7'], ['6', '18', '2'], ['1', '9', '7']]

Related

.join() gives back list as a result in python

Could someone, please, explain why .join() behaves in the following way:
input = [1, 0, 5, 3, 4, 12, 19]
a = " ".join(str(input))
print(a)
And the result is:
[ 1 , 0 , 5 , 3 , 4 , 1 2 , 1 9 ]
Not only is there still a list, but also an additional space.
How come?
When I use map() it works:
a = " ".join(list(map(str, input)))
But I would like to know what is wrong with the .join method I'm using.
str(input) returns one string '[1, 0, 5, 3, 4, 12, 19]', so then join uses each character of the string as input (a string is an iterable, like a list), effectively adding a space between each.
The effect is more visible if we join with a -: '[-1-,- -0-,- -5-,- -3-,- -4-,- -1-2-,- -1-9-]'
In contrast, list(map(str, input)) converts each number to string, giving a list of strings (['1', '0', '5', '3', '4', '12', '19']), which join then converts to '1 0 5 3 4 12 19'
See #mozway's answer to understand .join()'s behavior.
To get what you want (using join), you should try this:
input = [1, 0, 5, 3, 4, 12, 19]
a = " ".join([str(i) for i in input])
print(a)
Output:
1 0 5 3 4 12 19

Assigning numbers to given string's letters

I am currently trying to finish a project which wants encode given paragraph using given matrix. I wanted to start make a letter list:
letterlist = np.array([" ","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"])
letterlist2 = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"
samplestr = "MEET ME MONDAY"
My goal is convert the letters to integer in order like A=1,B=2...Z=26 and " "=0. Then assign them to 1x3 arrays. like
But I couldn't even make a progress. First I tried make for loops to match same letter in the letter list and samplestr. Then if they are same, give the order in the letterlist as integer. But I didn't get any output.
for letter in samplestr:
for letter2 in letterlist:
if letter2==letter:
print("x") ## To see if I get any match
I don't know where did I wrong and how should I continue this. Would making dictionary make it easier to assign letters to integers? Need some advices. Thanks for your time.
The conversion to a number is done by converting the char to a ordinary number and then subtracting 64 because that is the starting ASCII-Index for 'A'
Code looks like this:
from math import ceil
samplestr = "MEET ME MONDAY"
# Pad string to be dividable by 3
samplestr = samplestr.ljust(ceil(len(samplestr)/3) * 3)
# "MEET ME MONDAY "
# Convert to number reprensentation
samplestr = [0 if c == ' ' else (ord(c)-64) for c in samplestr]
# [13, 5, 5, 20, 0, 13, 5, 0, 13, 15, 14, 4, 1, 25, 0]
# Split in chunks of 3
matrix = [samplestr[i:i+3] for i in range(0, len(samplestr), 3)]
print(matrix)
This produces the following output:
[[13, 5, 5], [20, 0, 13], [5, 0, 13], [15, 14, 4], [1, 25, 0]]
Yes, dictionary will make it easier to assign letters to integers but if your final goal is to convert the letters to integer in order like A=1, B=2...Z=26 and " "=0, then assigning indices to the letters will also do the job.
I don't have much knowledge of numpy, so I will do it simply like this:
letterlist2 = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"
samplestr = "MEET ME MONDAY "
l = []
s = []
for i in samplestr:
s.append(letterlist2.index(i))
if len(s) == 3:
l.append(s)
s = []
if s != []:
l.append(s)
print(l)
Output:
[[13, 5, 5], [20, 0, 13], [5, 0, 13], [15, 14, 4], [1, 25, 0]]
Use a dictionary (with a single list comprehension) to convert the letters to numbers (would probably be the fastest) and then reshape to have 3 columns (-1 will take care of number of rows):
convert = dict(zip(letterlist, np.arange(27)))
converted = np.array([convert[char] for char in samplestr])
#[13 5 5 20 0 13 5 0 13 15 14 4 1 25]
from math import ceil
#resize to closes upper multiple of 3
converted.resize(ceil(converted.size/3)*3)
#reshape to have 3 columns
converted = converted.reshape(-1,3)
output:
[[13 5 5]
[20 0 13]
[ 5 0 13]
[15 14 4]
[ 1 25 0]]
Here is another solution with a simple dictionary mapping and list comprehensions. Note that you don't need to hardcode letters, it's in the standard library.
from string import ascii_uppercase
chars = " " + ascii_uppercase
encode = {char:"{}".format(i) for i, char in enumerate(chars)}
def str2num(s):
return [[encode[char] for char in s[i:i+3]] for i in range(0, len(s), 3)]
s = "MEET ME MONDAY"
print(str2num(s))
which returns:
[['13', '5', '5'],
['20', '0', '13'],
['5', '0', '13'],
['15', '14', '4'],
['1', '25']]

Identifying where colum entry first changes sign and save entry row to file

I have a file with multiply entries, I would like to monitor where a given column entries first change sign (i.e negative to positive) so that I save that row where this first happens to another file. In the example below, i want to monitor the change in sign in the first column.
-1 2 3
-3 3 5
-1 4 9
-3 5 6
-2 7 7
1 3 5
2 4 5
-2 4 5
1 5 6
The code should save the line -2 7 7 to another file. This should be simply but am failing to do it
You can use zip() to process items in a list with their successor:
lines = [ [-1, 2, 3],
[-3, 3, 5],
[-1, 4, 9],
[-3, 5, 6],
[-2, 7, 7],
[1, 3, 5],
[2, 4, 5],
[-2, 4, 5],
[1, 5, 6]
]
col = 0
keepLine = [ a for a,b in zip(lines,lines[1:]) if a[col]*b[col]<0 ]
print(keepLine) # [[-2, 7, 7], [2, 4, 5], [-2, 4, 5]]
# iterative ...
col = 0
previousLine = None
for line in lines: # or [int(n.strip()) for n in file.readline().split(",")]
if previousLine and line[col]*previousLine[col] < 0:
print(previousLine)
previousLine = line
So I'll leave the part of reading from a file (for which there are many examples here or elsewhere) to you.
Once you do you'll have a list of lines. At this point you should use a 2-pointer approach or just an index even. Note, these lines will be string representations of the numeric entries. So you could use regular expressions to see if the line starts with a - or + or no sign (indicating positive). Or typecast or use a helper to keep it easy to manage.
def get_sign(line):
sign = line.split()[0] #This will be a list of strings like ['-1', '3', '3'] or ['2', '4', '7']
if int(sign) < 0: #That's why the need to cast to compare.
return -1
return 1
#in your program, after parsing the file and loading up the lines as a list of strings
curr_sign = get_sign(lines[0]) #This will either be -, +
for ind in range(len(lines)-1): #lines is from getting all the lines from the file
if curr_sign != get_sign(lines[ind+1]):
write_to_file(lines[ind])
break #if you only need the first sign change.
If you want all sign changes to be tracked similarly
#in your program, after parsing the file and loading up the lines as a list of strings
curr_sign = get_sign(lines[0]) #This will either be -, +
for ind in range(len(lines)-1): #lines is from getting all the lines from the file
if curr_sign != get_sign(lines[ind+1]):
write_to_file(lines[ind]) #You're writing the prev line to when the sign changed
if curr_sign < 0:
curr_sign = 1
else:
curr_sign = -1

Extract a block of rows from 2D numpy

I know this question might be trivial but I am in the learning process. Given numpy 2D array, I want to take a block of rows using slicing approach. For instance, from the following matrix, I want to extract only the first three rows, so from:
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]
[ 28 9 203 102]
[577 902 11 101]]
I want:
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
My code here actually still missing something. I appreciate any hint.
X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [28, 9, 203, 102], [577, 902, 11, 101]]
X = np.array(X)
X_sliced = X[3,:]
print(X_sliced)
Numpy matrices can be thought of as nested lists of lists. Element 1 is list 1, element 2 is list 2, and so on.
You can pull out a single row with x[n], where n is the row number you want.
You can pull out a range of rows with x[n:m], where n is the first row and m is the final row.
If you leave out n or m and do x[n:] or x[:m], Python will fill in the blank with either the start or beginning of the list. For example, x[n:] will return all rows from n to the end, and x[:m] will return all rows from the start to m.
You can accomplish what you want by doing x[:3], which is equivalent to asking for x[0:3].

How can i do this simple thing in Python from Matlab?

Simple Matlab code: e.g A(5+(1:3)) -> gives [A(6), A(7), A(8)]
In the above, A is a vector or a matrix. For instance:
A = [1 2 3 4 5 6 7 8 9 10];
A(5+(1:3))
ans =
6 7 8
Note that MATLAB indexing starts at 1, not 0.
How can i do the same in Python?
You are looking for slicing behavior
A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> A[5:8]
[6, 7, 8]
If A is some function that you want to call with parameters 6, 7, and 8, you could use a list comprehension.
answers = [A(6+i) for i in range(3)]
You want to do two things.
First, create a range (5 + (1:3)) which could be done in Python like range(number).
Second, apply a function to each range index. This could be done with map or a for loop.
The for loop solutions have been addressed, so here's a map based one:
result = map(A,your_range)
Use a list comprehension:
x = 5
f = 1 # from
t = 3 # till
print [x+i for i in range(f,t+1)]
If you are trying to use subscripts to create an array which is a subset of the whole array:
subset_list = A[6:8]
in python u can do it easily by A[5:5+3] . u can reference the values 5 and 3 by variables also like
b=5
c=3
a[b:b+c]

Categories

Resources