# Utility method to view submatrices

I implemented an utility method that is able to view an Array[n, m] in another smaller dimension [k, l], where n%k = 0 and m%l = 0.

Example:

              -- --     -- --
---   ---     |1 2|     |3 4|
|1 2 3 4|     |5 6|     |7 8|
|5 6 7 8|  => -- --(a0) -- --(a1)
|4 3 2 1|     -- --     -- --
|8 7 6 5|     |4 3|     |2 1|
---   ---     |8 7|     |6 5|
-- --(a2) -- --(a3)

public static IEnumerable<T[,]> ViewAsNByM<T>(this T[,] values, int n, int m)
{
var count = values.GetLength(0)*values.GetLength(1);
for (int i = 0; i < count/(n*m); ++i)
{
var matrix = new T[n, m];
for (int j = 0; j < n; ++j)
{
for (int k = 0; k < m; ++k)
{
matrix[j, k] = values[j + (i / m * n), (k + i*m)% values.GetLength(0)];
}
}
yield return matrix;
}
}


Nunit test:

[Test]
public void TestViewAsNbyM()
{
var numbers = new[,]
{
{1, 2, 3, 4},
{5, 6, 7, 8},
{4, 3, 2, 1},
{8, 7, 6, 5}
};

var aux = numbers.ViewAsNByM(2, 2).ToList();
Assert.AreEqual(4, aux.Count);

var a0 = new[,] {{1, 2}, {5, 6}};
var a1 = new[,] {{3, 4}, {7, 8}};
var a2 = new[,] { { 4, 3 }, { 8, 7 } };
var a3 = new[,] { { 2, 1 }, { 6, 5 } };

Assert.That(aux, Is.EquivalentTo(new[] {a0,a1,a2,a3}));
}


• I don't have any suggestions (right now) but I'm curious what is it for? ;-P – t3chb0t Aug 20 '16 at 9:55
• @t3chb0t I think I will be using it for a sudoku game. To view the whole board as 3,3 groups – Bruno Costa Aug 20 '16 at 9:56
• there is no validation in method you mentioned before n%k = 0 and m%l = 0 – Disappointed Aug 20 '16 at 11:34

• Your solution seems to work fine fine for square matrix(where n = m). However, when presented with non-square matrix, the result becomes purely sporadic. This may or may not be problematic, depending on which kind of matrix you have to deal with.
• Modulo % is quite expensive.
• You are copying the array item by item. It is not the best way to it, especially when you are copying a continuous section within an array (where m > 1)
• You should cache the result of values.GetLength(0), and more importantly values[0].GetLength(0), as they are expensive.

public static IEnumerable<T[,]> ViewAsNByM2<T>(this T[,] values, int n, int m)
{
int height = values.GetLength(0), width = values.GetLength(1);
int rows = height / n, columns = width / m;

for (int row = 0; row < rows; row++)
{
for (int column = 0; column < columns; column++)
{
var matrix = new T[n, m];
for (int i = 0; i < n; i++)
{
Array.ConstrainedCopy(
values, (row * n + i) * width + column * m,
matrix, i * m,
m);
}
yield return matrix;
}
}
}

• Array.ConstrainedCopy is a nice tip. It was also nice that you could avoid the modulo. – Bruno Costa Aug 24 '16 at 20:14

(k + i*m)% values.GetLength(0)

This should have been (k + i*m)% values[0].GetLength(0)

It seems my implementation is a bit stricter than stated. In matter of fact it only allows matrices where k=sqrt(n) and l=sqrt(m).

While my previous implementation was what I strictly needed to view an array of 9 by 9 as 3 by 3, the algorithm can be adjusted in order to support any divisor of (n, m), including 1. Meanwhile I also decided that I prefer using jagged arrays.

public static IEnumerable<T[][]> ViewAsNByM<T>(this T[][] values, int m, int n)
{
var count = values.GetLength(0)*values[0].GetLength(0);
for (int i = 0; i < count/(n*m); ++i)
{
var matrix = new T[m][];
for (int j = 0; j < m; ++j)
{
matrix[j] = new T[n];
for (int k = 0; k < n; ++k)
{
int idxRow = j + (i/(values[0].GetLength(0)/n))*m;
int idxCol = (k + i*n)%values[0].GetLength(0);
matrix[j][k] = values[idxRow][idxCol];
}
}
yield return matrix;
}
}


And a test

[Test]
public void TestViewAsNbyM6By6()
{
var numbers = new[]
{
new[] { 1, 2, 3, 4, 5, 6},
new[] { 5, 6, 7, 8, 9, 1},
new[] { 4, 3, 2, 1, 0, 9},
new[] { 8, 7, 6, 5, 4, 3},
new[] { 2, 1, 0, 9, 8, 7},
new[] { 6, 5, 4, 3, 2, 1}
};

var aux = numbers.ViewAsNByM(3, 3).ToList();
Assert.AreEqual(4, aux.Count);

var a0 = new[] { new[] { 1, 2, 3 }, new[] { 5, 6, 7 }, new [] {4, 3, 2} };
var a1 = new[] { new[] { 4, 5, 6 }, new[] { 8, 9, 1 }, new [] {1, 0, 9} };
var a2 = new[] { new[] { 8, 7, 6 }, new[] { 2, 1, 0 }, new[] { 6, 5, 4 } };
var a3 = new[] { new[] { 5, 4, 3 }, new[] { 9, 8, 7 }, new[] { 3, 2, 1 } };

Assert.That(aux, Is.EquivalentTo(new[] { a0, a1, a2, a3 }));
}

• do we need to review your question or answer ? – Disappointed Aug 24 '16 at 11:19
• @Disappointed Due to community rules you should review my question. The code is not that different anyway. If you have other issues that you detected please give a new answer. – Bruno Costa Aug 24 '16 at 11:44