Lotramus
Lotramus

Reputation: 59

Initialize an array from the dimensions of another array

Is there a method to initialize a non-jagged array based on the rank of another array? I don't want to use dynamic things/reflection.

I was thinking I could build a jagged array from the ground up every time using recursive functions but that seems slow + I only want nice rectangular arrays such as float[,].

(Or would it be possible to iteratively create a non-jagged array?)

Basically this is what I want.

Array func(Array x) 
{
    int rank = x.Rank;
    int[] shape = new int[rank];
    for(int i = 0; i < rank; i++)
    {
        shape[i] = x.GetLength(i);
    }
    Array ret = new float[shape];  // I want to do this
    // basically float[shape[0],shape[1],...] except 
    //  I dont know the length of shape beforehand
    
    // processing
    return ret;
}

Upvotes: 0

Views: 136

Answers (2)

G Wimpassinger
G Wimpassinger

Reputation: 821

If you do not consider Array.CreateInstance (see System.Array docs) as more dynamic as your JaggedArray implementation, you can create new array instances with the same layout with the following implementation

private static Array CreateSized<T>(Array sourceArray)
{
    int[] shape = new int[sourceArray.Rank];
    for (int i = 0; i < shape.Length; i++)
        shape[i] = sourceArray.GetLength(i);
    
    return Array.CreateInstance(typeof(T), shape);
}

Using CreateSized like so

int [] a =  { 1, 2, 4, 8 };
Array fa = CreateSized<float>(a);

int [,] b = { { 10, 20, 40, 80 }, {100, 200, 400, 800 } };
Array fb = CreateSized<decimal>(b);

You can use the methods GetValue and SetValue on your array. For writing a value into the array:

fb.SetValue((decimal)b[0, 3] * 3, 0, 3);

and for reading from the array:

fb.GetValue(0, 3) 

If you know the rank at the use of CreateSized you can cast the result and enforce compiletime verification on the number of dimensions.

var fb = (decimal[,])CreateSized<decimal>(b);

If you don't know the rank at compiletime, the compiler can't know the rank too.

You can also use dynamic for the newly created array. Here a small example

dynamic fc = CreateSized<double>(b);
fc[0, 2] = b[0, 2] * 3.141592;
Console.WriteLine(fc[0, 2]);

Here is a dotnetfiddle version.

Upvotes: 1

Lotramus
Lotramus

Reputation: 59

Anyway, I wrote a jagged array version

public static object JaggedArray<T>(params int[] shape)
{
    object[] ret = new object[shape[0]];
    if(shape.Length == 1)
    {
        return new T[shape[0]];
    } else
    {
        for(int i = 0; i < shape[0]; i++)
        {
            ret[i] = JaggedArray<T>(shape.SubArray(1, shape.Length-1));
        }
    }
    return ret;
}

Upvotes: 0

Related Questions