Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extension method for fill rectangular array in C#

Tags:

arrays

c#

.net

I want write extension method for fill multidimensional rectangular array. I know how to do it for the array with a fixed number of measurements:

public static void Fill<T>(this T[] source, T value)
{
    for (int i = 0; i < source.Length; i++)
        source[i] = value;
}
public static void Fill<T>(this T[,] source, T value)
{
    for (int i = 0; i < source.GetLength(0); i++)
        for (int j = 0; j < source.GetLength(1); j++)
            source[i, j] = value;
}
public static void Fill<T>(this T[,,] source, T value)
{
    for (int i = 0; i < source.GetLength(0); i++)
        for (int j = 0; j < source.GetLength(1); j++)
            for (int k = 0; k < source.GetLength(2); k++)
                source[i, j, k] = value;
}

Can I write one fill-method for all multidimensional rectangular array?

like image 945
AndreyAkinshin Avatar asked Dec 07 '09 14:12

AndreyAkinshin


2 Answers

You can change the fixed dimension parameter to an Array parameter so you can put the extension on any Array. Then I used recursion to iterate through each position of the array.

public static void Fill<T>(this Array source, T value)
{
    Fill(0, source, new long[source.Rank], value);
}

static void Fill<T>(int dimension, Array array, long[] indexes, T value)
{
    var lowerBound = array.GetLowerBound(dimension);
    var upperBound = array.GetUpperBound(dimension);
    for (int i = lowerBound; i <= upperBound; i++)
    {
        indexes[dimension] = i;
        if (dimension < array.Rank - 1)
        {
            Fill(dimension + 1, array, indexes, value);
        }
        else
        {
            array.SetValue(value, indexes);
        }
    }
}
like image 117
Jake Pearson Avatar answered Nov 11 '22 19:11

Jake Pearson


Here's a solution that does not use recursion (and is less complex):

   public static void FillFlex<T>(this Array source, T value)
    {

        bool complete = false;
        int[] indices = new int[source.Rank];
        int index = source.GetLowerBound(0);
        int totalElements = 1;

        for (int i = 0; i < source.Rank; i++)
        {
            indices[i] = source.GetLowerBound(i);
            totalElements *= source.GetLength(i);
        }
        indices[indices.Length - 1]--;
        complete = totalElements == 0;

        while (!complete)
        {
            index++;

            int rank = source.Rank;
            indices[rank - 1]++;
            for (int i = rank - 1; i >= 0; i--)
            {
                if (indices[i] > source.GetUpperBound(i))
                {
                    if (i == 0)
                    {
                        complete = true;
                        return;
                    }
                    for (int j = i; j < rank; j++)
                    {
                        indices[j] = source.GetLowerBound(j);
                    }
                    indices[i - 1]++;
                }
            }

            source.SetValue(value, indices);
        }
    }

This is modeled from the System.Array.ArrayEnumerator. This implementation should have a similar level of correctness as ArrayEnumerator and (based on a few spot checks) appears to function fine.

like image 1
Robert Venables Avatar answered Nov 11 '22 19:11

Robert Venables