Subdividing a 4×4 array into four 2×2 arrays [closed]

Posted on

Problem

I want to subdivide a 4×4 2d array into 4 2×2 arrays and I have figured out how to do this in a very crude way, but am having a tougher time with a more elegant general solution.

``````    for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 2; j++)
{
for (int k = 0; k < 2; k++)
{
int j2 = j;
int k2 = k;
if (i == 1) { k2 += 2; }
if (i == 2) { j2 += 2; }
if (i == 3) { j2 += 2; k2 += 2; }
twoByTwo[i][j, k] = fourByFour[j2, k2];
}
}
}
``````

Solution

Flatten and copy array values

You can flatten your `fourByFour` array and then populate the `twoByTwo` array:

``````private static object convertArray1()
{
int[,] fourByFour = new int[,]{
{1,2,3,4 },
{12,13,14,15 },
{21,22,23,24 },
{31,32,33,34 } };

int[] arrayElems = new int[fourByFour.GetLength(0) * fourByFour.GetLength(1)];

Buffer.BlockCopy(fourByFour, 0, arrayElems, 0, arrayElems.Length * sizeof(int));

int[][,] twoByTwo = new int[4][,];

int elemIndex = 0;
for (int i = 0; i < twoByTwo.GetLength(0); i++)
{
twoByTwo[i] = new int[2, 2];

for (int j = 0; j < twoByTwo[i].GetLength(0); j++)
{
for (int k = 0; k < twoByTwo[i].GetLength(1); k++)
{
twoByTwo[i][j, k] = arrayElems[elemIndex];
elemIndex++;
}
}
}

return twoByTwo;
}
``````

This solution has a performance penalty – `Buffer.BlockCopy` copies the source array `fourByFour` an extra time (which will also require additional memory).

Dimension counter class

Use a helper class to keep track of and increment index positions in each dimension.

This solution is more generic.

``````private static object convertArray2()
{
int[,] fourByFour = new int[,]{
{1,2,3,4 },
{12,13,14,15 },
{21,22,23,24 },
{31,32,33,34 } };

DimensionCounter dim1 = new DimensionCounter(4, 4);
DimensionCounter dim2 = new DimensionCounter(4, 2, 2);

int[][,] twoByTwo = new int[4][,];

for (int i = 0; i < dim1.Capacity; i++)
{
int val = (int)fourByFour.GetValue(dim1.Current);

if (twoByTwo[dim2.Current[0]] == null)
{
twoByTwo[dim2.Current[0]] = new int[dim2.DimensionSizes[1], dim2.DimensionSizes[2]];
}

twoByTwo[dim2.Current[0]][dim2.Current[1], dim2.Current[2]] = val;

if (i + 1 < dim1.Capacity)
{
dim1.Next();
dim2.Next();
}
}

return twoByTwo;
}

private class DimensionCounter
{

private int[] dimIndexes;
private int position;

public int[] DimensionSizes { get { return dimSizes; } }
public int[] Current
{
get { return dimIndexes; }
}
public int Position { get { return position; } }
public int Capacity { get { return capacity; } }
public DimensionCounter(params int[] dimSizes)
{
this.dimSizes = dimSizes;
this.capacity = dimSizes.Aggregate(1, (a, b) => a * b);
this.dimIndexes = new int[this.dimSizes.Length];
}

public int[] Next()
{
for (int i = dimIndexes.Length - 1; i >= 0; i--)
{
if (dimIndexes[i] < dimSizes[i] - 1)
{
dimIndexes[i]++;
break;
}
else
{
for (int j = i; j < dimIndexes.Length; j++)
{
dimIndexes[j] = 0;
}

if (i == 0)
{
throw new IndexOutOfRangeException("Cannot increment indexes any more!");
}
}
}
position++;
return dimIndexes;
}

public void Reset()
{
dimIndexes = new int[dimIndexes.Length];
position = 0;
}
}
``````

``````public static int[][,] Partition4By4(int[,] arr) {