Reputation: 2743
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
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
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