2
votes

Scenario

Using Python, I need to write a 2d matrix into a file in order to allow the following command to easily read it:

with open("matrix.txt") as textFile:
    matrix = [line.split() for line in textFile]

Problem

I have tried file.write(str(matrix)) and it writes it alright but it doesn't lay it how I need it to be to the later extract the data.

What I have is the following:

[[1, 2, 3,][4, 5, 6][7, 8, 9]]

Expected Solution

What I want the file to have;

1 2 3
4 5 6
7 8 9

Any ideas???

3

3 Answers

3
votes

You can convert individual rows of your matrix into strings separated by spaces and write those into a text file.

matrix = [[1, 2, 3,],[4, 5, 6],[7, 8, 9]]

with open('matrix.txt', 'w') as testfile:
    for row in matrix:
        testfile.write(' '.join([str(a) for a in row]) + '\n')
1
votes

If you just need to write the data and be able to retrieve it later from a Python program, the "text" file constraing just complicates things.

That is because Python ships with the pickle module, which can serialize all kinds of objects which make sense to be serializable, and retrieve them later from a file in a seamless way.

In this case, if your "matrix" is on a variable with that name, all the code you need is:

import pickle
pickle.dump(matrix, open("myfile.bin", "wb"))

And to retrieve it later:

import pickle
matrix = pickle.load(open("myfile.bin", "rb"))

Now, if you need it to be text and human readable, and your matrices are just lists within lists with numeric elements, and no arbitrary objects, the json module will work just the same, and produce a file that not only is human readable, but can be understood under a host of other languages and libraries:

import json
json.dump(matrix, open("myfile.bin", "wb"))

# retrieve: 
matrix = json.load(open("myfile.bin", "rb"))

rolling out your own code

Of course, for learning purposes, and getting real solid grasp on program, being able to write your own matrix and read it back is an invaluable exercise. Just keep in mind that it is good for you learning and training, but not good if this is just a small part of a real world problem - this would be reinventing the wheel over a detail, and yo should use one of the methods above.

For DIY, the bad news first: a file, and a text file as well, can accept anything you write to it. So you have to lay out conventions on what symbols you will use to indicate the matrix size, if it is not always fixed in 3x3 and take care of that on writting and on reading. (note that you could simply sabe the repr output for your matrix, an use eval on its contents on reading - for Python literal values, that would work, but then you could just use pickle or json).

Since you wrote your desired output in the question, that makes it easier: we are going for space separated numbers, one row of the file for each row in the matrix.

It is just a matter of creating the outter matrix, reading a line from the file, calling .split on it, so that you have one string containing each number, map each of these tokens through "int", and create a new list, that is one of the rows.

That is, step by step:


def read_matrix(path):
    matrix = []
    with open(path) as file:
        for row in file:
            if not row.strip():
                # skip blank lines
                continue
            matrix_row = []
            for token in row.split():
                matrix_row.append(int(token))
            matrix.append(matrix_row)
    return matrix

Or using Python expressiveness and list comprehensions, the same code in a single line is:


def read_matrix(path):
    return [[int(token) for token in row.split()]  for row in open(path) if row.strip()]

Writing the file

Writting such a file is as easy as interating element by element of your matrix and outputing it to disk:


def write_matrix(path, matrix):
    with open(path, "wt"):
        for row in matrix:
            for item in row:
                file.write(str(item) + " ")
            file.write("\n")

This writes an extra " " on the end of each row, but there are several approaches to avoid that. One of the easier would be to compose the row as a string using Python string formatting methods


def write_matrix(path, matrix):
    with open(path, "wt"):
        for row in matrix:
            file.write(" ".join(str(item) for item in row) + "\n")
0
votes

You can use numpy.savetxt:

import numpy as np

a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

np.savetxt(filename, a, fmt='%i')