So I have an object called, for lack of a better word, MatricesMatrix
which is a Matrix
of Matrices (everything is stored as a double[,]
). I want to strip all of the values from the inner matrices into one big Matrix. Here is what I have so far:
public Matrix ConvertToMatrix()
{
//Figure out how big the return matrix should be
int totalRows = this.TotalRows();
int totalColumns = this.TotalColumns();
Matrix returnMatrix = new Matrix(totalRows, totalColumns);
List<object> rowElementsList = new List<object>();
//"outer" index means an index of the MatricesMatrix
//"inner" index means an index of a Matrix within the Matrices Matrix
//outer row loop
for (int outerRowIndex = 0; outerRowIndex < NumberOfRows; outerRowIndex++)
{
//outer column loop
for (int outerColumnIndex = 0; outerColumnIndex < NumberOfColumns; outerColumnIndex++)
{
Matrix currentMatrix = GetElement(outerRowIndex, outerColumnIndex);
object element = null;
//inner row loop
for (int innerRowIndex = 0; innerRowIndex < currentMatrix.NumberOfRows; innerRowIndex++)
{
//inner column loop
for (int innerColumnIndex = 0; innerColumnIndex < currentMatrix.NumberOfColumns; innerColumnIndex++)
{
element = currentMatrix.GetElement(innerRowIndex, innerColumnIndex);
}
}
returnMatrix.SetElement(outerRowIndex, outerColumnIndex, (double)element);
}
}
return returnMatrix;
}
Note that I have determined programmatically the total number of rows and columns the returnMatrix needs to have.
Here are some more guidelines and output cases:
CASE 1
Given this input: a MatricesMatrix(2,2)
with [0,0] = (2x2 matrix), [0,1] = (2x3 matrix), [1,0] = (2x2 matrix), and [1,1] = (2x3 matrix)
. That is,
Output must be:
CASE 2
Given this input: a MatricesMatrix(2,2)
with [0,0] = (1x1 matrix), [0,1] = (3x3 matrix), [1,0] = (2x2 matrix), and [1,1] = (4x4 matrix)
. That is,
Output should be something like:
Any assistance would be greatly appreciated!
UPDATE: Here is a unit test for Case 1 that should pass:
[TestMethod]
public void MatricesMatrix_ConvertToMatrixTest()
{
Matrix m1 = new Matrix(2);
Matrix m2 = new Matrix(2, 3);
Matrix m3 = new Matrix(2);
Matrix m4 = new Matrix(2, 3);
double[] m1Row1 = { 1, 1 };
double[] m1Row2 = { 1, 1 };
double[] m2Row1 = { 2, 2, 2 };
double[] m2Row2 = { 2, 2, 2 };
double[] m3Row1 = { 3, 3 };
double[] m3Row2 = { 3, 3 };
double[] m4Row1 = { 4, 4, 4 };
double[] m4Row2 = { 4, 4, 4 };
m1.SetRowOfMatrix(0, m1Row1);
m1.SetRowOfMatrix(1, m1Row2);
m2.SetRowOfMatrix(0, m2Row1);
m2.SetRowOfMatrix(1, m2Row2);
m3.SetRowOfMatrix(0, m3Row1);
m3.SetRowOfMatrix(1, m3Row2);
m4.SetRowOfMatrix(0, m4Row1);
m4.SetRowOfMatrix(1, m4Row2);
MatricesMatrix testMatricesMatrix = new MatricesMatrix(2, 2);
testMatricesMatrix.SetElement(0, 0, m1);
testMatricesMatrix.SetElement(0, 1, m2);
testMatricesMatrix.SetElement(1, 0, m3);
testMatricesMatrix.SetElement(1, 1, m4);
Matrix expectedResult = new Matrix(4, 5);
double[] expectedRow1 = { 1, 1, 2, 2, 2 };
double[] expectedRow2 = { 1, 1, 2, 2, 2 };
double[] expectedRow3 = { 3, 3, 4, 4, 4 };
double[] expectedRow4 = { 3, 3, 4, 4, 4 };
expectedResult.SetRowOfMatrix(0, expectedRow1);
expectedResult.SetRowOfMatrix(1, expectedRow2);
expectedResult.SetRowOfMatrix(2, expectedRow3);
expectedResult.SetRowOfMatrix(3, expectedRow4);
Matrix actualResult = testMatricesMatrix.ConvertToMatrix();
(actualResult == expectedResult).Should().BeTrue();
}
I started with a simple Matrix class to hold the double[,]
s. Nothing too fancy, just a simple array-of-arrays with a row and column count and array accessor.
class Matrix<T>
{
public int Rows { get; private set; }
public int Cols { get; private set; }
private T[,] mat;
public Matrix(int rowCount, int colCount)
{
Rows = rowCount;
Cols = colCount;
mat = new T[Rows, Cols];
}
public T this[int r, int c]
{
get { return mat[r, c]; }
set { mat[r, c] = value; }
}
}
Your second case looks more difficult (and like a better test of correctness) than the first, so I set up a metamatrix to match that.
public static Matrix<double[,]> BuildMetaMatrix()
{
Matrix<double[,]> m = new Matrix<double[,]>(2, 2);
m[0, 0] = new double[,]
{
{ 1 }
};
m[0, 1] = new double[,]
{
{ 3, 3, 3 },
{ 3, 3, 3 },
{ 3, 3, 3 }
};
m[1, 0] = new double[,]
{
{ 2, 2 },
{ 2, 2 }
};
m[1, 1] = new double[,]
{
{4, 4, 4, 4},
{4, 4, 4, 4},
{4, 4, 4, 4},
{4, 4, 4, 4}
};
return m;
}
For convenience, I made a Place function that puts one matrix into another one at the given location.
static void Place(double[,] src, double[,] dest, int destR, int destC)
{
for (int row = 0; row < src.GetLength(ROW_DIM); row++)
{
for (int col = 0; col < src.GetLength(COL_DIM); col++)
{
dest[row + destR, col + destC] = src[row, col];
}
}
}
The magic numbers fed into GetLength()
were just asking for mistakes, so I defined some constants for them (ROW_DIM = 0
and COL_DIM = 1
). I decided to handle the padding by figuring out how wide a column is and how tall a row is and skipping any extra elements after Place()
ing the sub-matrix in. A GetRowHeight()
and GetColWidth()
method figure out the values.
public static int GetRowHeight(Matrix<double[,]> m, int row)
{
int maxSeen = 0;
for (int col = 0; col < m.Cols; col++)
{
if (m[row, col].GetLength(ROW_DIM) > maxSeen)
{
maxSeen = m[row, col].GetLength(ROW_DIM);
}
}
return maxSeen;
}
public static int GetColWidth(Matrix<double[,]> m, int col)
{
int maxSeen = 0;
for (int row = 0; row < m.Rows; row++)
{
if (m[row, col].GetLength(COL_DIM) > maxSeen)
{
maxSeen = m[row, col].GetLength(COL_DIM);
}
}
return maxSeen;
}
A Flatten()
function loops through all the sub-matrices, Place()
ing them at the appropriate row and column in a new matrix. It updates the next row and column after each Place()
using the GetRowHeight()
and GetColWidth()
functions.
Matrix<double> Flatten(Matrix<Matrix<double>> src)
{
// (7, 6) == (this.TotalRows(), this.TotalColumns())
// from your code.
Matrix<double> dest = new Matrix<double>(7, 6);
int nextRow = 0;
int nextCol = 0;
for (int row = 0; row < src.Rows; row++)
{
for (int col = 0; col < src.Rows; col++)
{
dest.Place(src[row, col], nextRow, nextCol);
nextCol += GetColWidth(src, col);
}
nextRow += GetRowHeight(src, row);
nextCol = 0;
}
return dest;
}
A little glue to test it out...
static void Main(string[] args)
{
Matrix<double[,]> src = BuildMetaMatrix();
double[,] dest = Flatten(src);
Print(dest);
Console.ReadLine();
}
static void Print(double[,] matrix)
{
for (int row = 0; row < matrix.GetLength(ROW_DIM); row++)
{
for (int col = 0; col < matrix.GetLength(COL_DIM); col++)
{
Console.Write(matrix[row, col] + "\t");
}
Console.Write("\n");
}
}
...and you get an output just like your second case with all the oddly fitting matrices and 0
s in the empty places.*
1 0 3 3 3 0
0 0 3 3 3 0
0 0 3 3 3 0
2 2 4 4 4 4
2 2 4 4 4 4
0 0 4 4 4 4
0 0 4 4 4 4
*The destination matrix gets its values initialized to default(double)
, which happens to be 0
(the value you wanted). If you need something other than default(double)
for the empty places, you can probably get them by iterating over the new matrix and writing the new default value everywhere before Flatten()
ing the metamatrix.
(Thanks to Jeff Mercado for pointing out that multidimensional arrays' GetLength()
method can be used to find their dimensions.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With