Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a 1-Dimensional Array in C# with index starting at 1

For multidimensional arrays Array.CreateInstance can be used to create non-zero index based arrays, but if you try that for a 1-dimensional arrays (vectors) as in e.g.:

public double[] myArray = (double[])Array.CreateInstance(typeof(double), new int[1] { 12 }, new int[1] { 1 });

this will fail at run-time when the cast from the the multidimensional Array to a single-dimensional array fails

"Unable to cast object of type 'System.Double[*]' to type 'System.Double[]'"

Now I could just create a zero based array and ignore the first value, or work with offsets etc., but am I overlooking some c# syntactic magic that allows for non zero based vectors?

Update:

I'll take Eric Lippert's word for it if he says "There's no obvious way to make a non-zero-based array in C#"

like image 921
Peter Stuer Avatar asked Apr 20 '11 09:04

Peter Stuer


People also ask

What is a 1 dimensional array?

Definition. A One-Dimensional Array is the simplest form of an Array in which the elements are stored linearly and can be accessed individually by specifying the index value of each element stored in the array.

What is a one-dimensional array How can we initialize it?

One way is to initialize one-dimentional array is to initialize it at the time of declaration. You can use this syntax to declare an array at the time of initialization. int a[5] = {10, 20, 30, 40, 50}; a[0] is initialized with 10, a[1] is initialized with 20 and so on.


2 Answers

You can make a non-zero-based array in C#, but the useage of it is kind-of obnoxious. It is definitly not a simple substitute for a normal (i.e., zero-based single dimentional) array.

        // Create the array.
        Array myArray = Array.CreateInstance(typeof(double), new int[1] { 12 }, new int[1] { 1 });

        // Fill the array with random values.
        Random rand = new Random();
        for (int index = myArray.GetLowerBound(0); index <= myArray.GetUpperBound(0); index++)
        {
            myArray.SetValue(rand.NextDouble(), index);
        }

        // Display the values.
        for (int index = myArray.GetLowerBound(0); index <= myArray.GetUpperBound(0); index++)
        {
            Console.WriteLine("myArray[{0}] = {1}", index, myArray.GetValue(index));
        }

The GetValue/SetValue syntax that is required for this is uglier than subtracting one from a vector index at each occurance.

If a value type is stored in the array, then it will be stored in consecutive position just as in a regular array, but the getter and setter will require boxing of the values (unless there is some compiler magic that I am not aware of). And the getter will usually require a cast (just to make it even uglier).

    double myValue = (double)myArray.GetValue(index);

Also note that the correct comparison for GetUpperBound is <=, unlike Length which is compared with <.

like image 136
Jeffrey L Whitledge Avatar answered Sep 26 '22 23:09

Jeffrey L Whitledge


Non-Zero based arrays DO exist in C, and there IS a way to create a 1's (or whatever) based array.

I fully agree that they are messy, and they should not be used for anything other than legacy stuff, but they are ESSENTIAL to interact with old COM libraries.

The most common place to run into this is working with the Microsoft.Office.Interop.Excel.Range object in the Excel library which still uses the old DCOM interface underneath.

Example:

/// <summary>
    /// Makes the equivalent of a local Excel range that can be populated 
    ///  without leaving .net
    /// </summary>
    /// <param name="iRows">number of rows in the table</param>
    /// <param name="iCols">number of columns in the table</param>
    /// <returns>a 1's based, 2 dimensional object array which can put back to Excel in one DCOM call.</returns>
    public static object[,] NewObjectArray(int iRows, int iCols)
    {

        int[] aiLowerBounds = new int[] { 1, 1 };
        int[] aiLengths = new int[] { iRows, iCols};

        return (object[,])Array.CreateInstance(typeof(object), aiLengths, aiLowerBounds);

    }

In this case, the reason this code is necessary is each DCOM call to excel is a cross-process call, and if you were to access cells one-at-a-time, you'd incur huge overhead, (either retrieving or setting values). An Excel range is a 1's based 2 dimensional array, and if one creates the array, and populates it locally, it can be pushed to excel in one cross-process call, creating an enormous performance improvement.

like image 39
mike Avatar answered Sep 24 '22 23:09

mike