In C#, there are three types of arrays: one-dimensional, jagged, and multi-dimensional rectangular.
The question is: given an array of a specific size, how can we cr
Use Array.CreateInstance(Type, Int32[]) method to create an array of an arbitrary size.
But the problem, you will have after creating this array is: How do you efficiently access the elements of the array if you don't know its rank?
You may use myArray.GetValue(Int32[]) and myArray.SetValue(Object, Int32[]) but I assume the performance is no that good.
To sum up:
public static Array CreateArray(Array array)
{
// Gets the lengths and lower bounds of the input array
int[] lowerBounds = new int[array.Rank];
int[] lengths = new int[array.Rank];
for (int numDimension = 0; numDimension < array.Rank; numDimension++)
{
lowerBounds[numDimension] = array.GetLowerBound(numDimension);
lengths[numDimension] = array.GetLength(numDimension);
}
Type elementType = array.GetType().GetElementType(); // Gets the type of the elements in the input array
return Array.CreateInstance(elementType, lengths, lowerBounds); // Returns the new array
}
I've done a little benchmark to compare performance of the array indexer and the GetValue, SetValue versions.
Here is the code I used:
const int size = 10000000;
object[] array1 = new object[size];
object[] array2 = new object[size];
Random random;
random = new Random(0);
for (int i = 0; i < size; i++)
{
array1[i] = random.Next();
array2[i] = random.Next();
}
Stopwatch stopwatch = new Stopwatch();
Console.ReadKey();
stopwatch.Restart();
for (int i = 0; i < size; i++)
array1[i] = array2[i];
stopwatch.Stop();
Console.WriteLine("Indexer method: {0}", stopwatch.Elapsed);
random = new Random(0);
for (int i = 0; i < size; i++)
{
array1[i] = random.Next();
array2[i] = random.Next();
}
Console.ReadKey();
stopwatch.Restart();
for (int i = 0; i < size; i++)
array1.SetValue(array2.GetValue(i), i);
stopwatch.Stop();
Console.WriteLine("Get/SetValue method: {0}", stopwatch.Elapsed);
The result are:
Indexer method: 0.014 s
Set/GetValue method: 1.33 s
The result are slightly different if I replace the int
by object
.
Indexer method: 0.05 s
Set/GetValue method: 0.54 s
This can be easily explained by the necessary boxing/unboxing when using integer with Set/GetValue
.
You can use reflection-like methods:
You can populate an array of lengths (one per rank) based on the existing array, and then use Array.CreateInstance(Type, int[]). So:
public static Array CreateNewArrayOfSameSize(Array input)
{
int[] lengths = new int[input.Rank];
for (int i = 0; i < lengths.Length; i++)
{
lengths[i] = input.GetLength(i);
}
return Array.CreateInstance(array.GetType().GetElementType(), lengths);
}
It's a shame there isn't a method to return all the lengths in one go, but I can't see one. Also I'm surprised that there isn't an ElementType
property on Array
, but again it may just be eluding me.
Note that this doesn't attempt to maintain the same upper/lower bounds for each dimension as the original array - just the sizes.