msalafia
msalafia

Reputation: 2743

C# - Change a multi-dimensional Array element Type

I have a multi-dimensional Array with unknown dimensions at compile time but at runtime (when i receive such Array) its dimension are described int[] dimensions. The length of dimensions is equal to the Rank of the Array and each element of dimensions contains the length of the relevant dimension.

What i want to obtain is a similar Array whose elements are mapped in a new object with a different type. I thought that LINQ could be useful so i wrote the following:

Array arr = ... //My multi-dimensional Array
var dimensions = ... //array describing the dimensions of arr. (NOT USED in the following but is an information i have)

var transformedArr = arr.Cast<StatusCode>().Select(val => JObject.FromObject(val)).ToArray();

It works but transformedArr is just a one-dimension Array now, hence i lost my multi-dimensional matrix. Have you got any idea to obtain a same Array with different element type only?

Please, note that i don't know a priori the dimensions of the array, only at runtime. In other words i can't use loops for indexing the multi-dimensional Array.

Any idea will be appreciated :)

Upvotes: 1

Views: 339

Answers (2)

khoroshevj
khoroshevj

Reputation: 1137

I think following function should meet your requirements

public static void RecursiveCopy<TInput, TOutput>(
    Array source,
    Array destination,
    int[] dimensions,
    Func<TInput, TOutput> mutate,
    int[] indexPrefix = null)
{
    indexPrefix = indexPrefix ?? new int[0];
    if (dimensions.Length != 1)
    {
        for (var i = 0; i < dimensions[0]; i++)
        {
            var newDimensions = new int[dimensions.Length - 1];
            Array.Copy(dimensions, 1, newDimensions, 0, dimensions.Length - 1);

            var newIndexPrefix = new int[indexPrefix.Length + 1];
            Array.Copy(indexPrefix, 0, newIndexPrefix, 0, indexPrefix.Length);
            newIndexPrefix[indexPrefix.Length] = i;

            RecursiveCopy(source, destination, newDimensions, mutate, newIndexPrefix);
        }
    }
    else
    {
        var currentIndex = new int[indexPrefix.Length + 1];
        Array.Copy(indexPrefix, 0, currentIndex, 0, indexPrefix.Length);
        for (var i = 0; i < dimensions[0]; i++)
        {
            currentIndex[indexPrefix.Length] = i;
            var value = source.GetValue(currentIndex);
            if (value is TInput)
            {
                var mutated = mutate((TInput)value);
                destination.SetValue(mutated, currentIndex);
            }
            else
            {
                throw new ArgumentException("Different type. Expected " + nameof(TInput));
            }
        }
    }
}

Usage

var transformedArr = Array.CreateInstance(typeof(StatusCode), dimensions);
RecursiveCopy<object, StatusCode>(arr, transformedArr, dimensions, i => i as StatusCode);

You can put real type instead of object

Upvotes: 1

Amit
Amit

Reputation: 46361

You can do this by using CreateInstance to create your output array (using your dimensions as input), then using GetValue and SetValue to transform your values.

Upvotes: 0

Related Questions