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 readonly int[] dimSizes;
    private readonly int capacity;

    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;
    }
}

What about this:?

public static int[][,] Partition4By4(int[,] arr) {
    return new int[][,] {
        {{arr[0,0], arr[1,0]}, {arr[0,1], arr[1,1]}},
        {{arr[0,2], arr[1,2]}, {arr[0,3], arr[1,3]}},
        {{arr[2,0], arr[3,0]}, {arr[2,1], arr[3,1]}},
        {{arr[2,2], arr[3,2]}, {arr[2,3], arr[3,3]}}};
}

It’s fast and simple.

Leave a Reply

Your email address will not be published. Required fields are marked *