Programmatically Declare Array of Arbitrary Rank

后端 未结 3 597
走了就别回头了
走了就别回头了 2021-01-14 01:29

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

3条回答
  •  天命终不由人
    2021-01-14 02:00

    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
    }
    

    Update

    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.

提交回复
热议问题