How to set array length in c# dynamically
Asked Answered
E

9

33

I am still new to C# and I've been struggling with various issues on arrays. I've got an array of metadata objects (name value pairs) and I would like to know how to create only the number of "InputProperty" objects that I truly need. In this loop I've arbitrarily set the number of elements to 20 and I try to bail out when the entry becomes null but the web service on the receiving end of this does not like any null elements passed to it:

private Update BuildMetaData(MetaData[] nvPairs)
{
    Update update = new Update();
    InputProperty[] ip = new InputProperty[20];  // how to make this "dynamic"
    int i;
    for (i = 0; i < nvPairs.Length; i++)
    {
        if (nvPairs[i] == null) break;
        ip[i] = new InputProperty();
        ip[i].Name = "udf:" + nvPairs[i].Name;
        ip[i].Val = nvPairs[i].Value;
    }
    update.Items = ip;
    return update;
}

In summary, say I only have 3 namevalue pairs in the above input array? Rather than allocate 20 elements for the array called ip, how can code this so ip is only as big as it needs to be. The update object is passed across another webservice so serialization is important (i.e. I can't use namevaluecollection, etc.).

p.s. Is the only way to followup on a posted question through the "add comments" facility?

Edana answered 25/3, 2009 at 19:27 Comment(0)
E
24

If you don't want to use a List, ArrayList, or other dynamically-sized collection and then convert to an array (that's the method I'd recommend, by the way), then you'll have to allocate the array to its maximum possible size, keep track of how many items you put in it, and then create a new array with just those items in it:

private Update BuildMetaData(MetaData[] nvPairs)
{
    Update update = new Update();
    InputProperty[] ip = new InputProperty[20];  // how to make this "dynamic"
    int i;
    for (i = 0; i < nvPairs.Length; i++)
    {
        if (nvPairs[i] == null) break;
        ip[i] = new InputProperty(); 
        ip[i].Name = "udf:" + nvPairs[i].Name;
        ip[i].Val = nvPairs[i].Value;
    }
    if (i < nvPairs.Length)
    {
        // Create new, smaller, array to hold the items we processed.
        update.Items = new InputProperty[i];
        Array.Copy(ip, update.Items, i);
    }
    else
    {
        update.Items = ip;
    }
    return update;
}

An alternate method would be to always assign update.Items = ip; and then resize if necessary:

update.Items = ip;
if (i < nvPairs.Length)
{
    Array.Resize(update.Items, i);
}

It's less code, but will likely end up doing the same amount of work (i.e. creating a new array and copying the old items).

Evaporate answered 25/3, 2009 at 19:53 Comment(0)
V
35
InputProperty[] ip = new InputProperty[nvPairs.Length]; 

Or, you can use a list like so:

List<InputProperty> list = new List<InputProperty>();
InputProperty ip = new (..);
list.Add(ip);
update.items = list.ToArray();

Another thing I'd like to point out, in C# you can delcare your int variable use in a for loop right inside the loop:

for(int i = 0; i<nvPairs.Length;i++
{
.
.
}

And just because I'm in the mood, here's a cleaner way to do this method IMO:

private Update BuildMetaData(MetaData[] nvPairs)
{
        Update update = new Update();
        var ip = new List<InputProperty>();

        foreach(var nvPair in nvPairs)
        {
            if (nvPair == null) break;
            var inputProp = new InputProperty
            {
               Name = "udf:" + nvPair.Name,
               Val = nvPair.Value
            };
            ip.Add(inputProp);
        }
        update.Items = ip.ToArray();
        return update;
}
Viera answered 25/3, 2009 at 19:30 Comment(6)
I think you're missing the problem here -- the input array, nvPairs, contains null values after the useful ones. Simply using its length won't solve anything.Joanjoana
The OP never specified that. I just assumed the if null was a simple sanity check. If what you're saying is in fact the case, then you're right. List would definitely be the way to go.Viera
Hmm I didn't consider it might be a sanity check. That's certainly possible.Joanjoana
Whatsit is correct (input array nvPairs contains null entries after the useful ones. I tried the "cleaner" way offered by BFree above with slight change to get around compile time errors.Edana
If array called ip is allocated same length as nvPairs, how does the above code get array ip populated with objects. I see inside the foreach loop the creation of an InputProperty object, but I don't see how these objects get added to array ip.Edana
OK, I edited my post. It's now using a list, and correctly adding the new InputProperty objects. I'm typing the code directly into the answer box, so if there are syntax errors, I aplogize.Viera
E
24

If you don't want to use a List, ArrayList, or other dynamically-sized collection and then convert to an array (that's the method I'd recommend, by the way), then you'll have to allocate the array to its maximum possible size, keep track of how many items you put in it, and then create a new array with just those items in it:

private Update BuildMetaData(MetaData[] nvPairs)
{
    Update update = new Update();
    InputProperty[] ip = new InputProperty[20];  // how to make this "dynamic"
    int i;
    for (i = 0; i < nvPairs.Length; i++)
    {
        if (nvPairs[i] == null) break;
        ip[i] = new InputProperty(); 
        ip[i].Name = "udf:" + nvPairs[i].Name;
        ip[i].Val = nvPairs[i].Value;
    }
    if (i < nvPairs.Length)
    {
        // Create new, smaller, array to hold the items we processed.
        update.Items = new InputProperty[i];
        Array.Copy(ip, update.Items, i);
    }
    else
    {
        update.Items = ip;
    }
    return update;
}

An alternate method would be to always assign update.Items = ip; and then resize if necessary:

update.Items = ip;
if (i < nvPairs.Length)
{
    Array.Resize(update.Items, i);
}

It's less code, but will likely end up doing the same amount of work (i.e. creating a new array and copying the old items).

Evaporate answered 25/3, 2009 at 19:53 Comment(0)
M
8

Use this:

 Array.Resize(ref myArr, myArr.Length + 5);
Minotaur answered 8/8, 2012 at 12:41 Comment(0)
P
5

Does is need to be an array? If you use an ArrayList or one of the other objects available in C#, you won't have this limitation to content with. Hashtable, IDictionnary, IList, etc.. all allow a dynamic number of elements.

Prevailing answered 25/3, 2009 at 19:31 Comment(7)
I agree. If you need the functionality of an array and have dynamic length, an ArrayList is the most simple and obvious answer.Idelson
ArrayList? Are we allergic to generics?Evaporate
michl86 comments that use of List and .ToArray at the end is too slow. Looks like ArrayList can be converted to array in same manner. For my final result I need an array not ArrayList. Is performance that bad with .ToArray() just before return?Edana
Haha - generic are cool too. I was trying to keep it as close to what he was using as possible.Prevailing
The webservice I have to pass this object to wants an array of InputProperty objects where there are no null entries.Edana
"Too slow" is relative, and in this case irrelevant. It's highly unlikely that the time required for ToArray() will make a dent in the latency between your application and the Web service.Evaporate
I don't think @michl86 meant "too slow" as in performance, but instead meant "too slow" as in @Viera beat him to the answer.Sciatic
I
2

You could use List inside the method and transform it to an array at the end. But i think if we talk about an max-value of 20, your code is faster.

    private Update BuildMetaData(MetaData[] nvPairs)
    {
        Update update = new Update();
        List<InputProperty> ip = new List<InputProperty>();
        for (int i = 0; i < nvPairs.Length; i++)
        {
            if (nvPairs[i] == null) break;
            ip[i] = new InputProperty();
            ip[i].Name = "udf:" + nvPairs[i].Name;
            ip[i].Val = nvPairs[i].Value;
        }
        update.Items = ip.ToArray();
        return update;
    }
Imbricate answered 25/3, 2009 at 19:34 Comment(1)
Adapted code above. Getting "The type or namespace name 'List' could not be found (are you missing a using directive or an assembly reference?) I have this too (what else could he want): using System.Collections; using System.Collections.Generic; using System.Collections.Specialized;Edana
P
2

Or in C# 3.0 using System.Linq you can skip the intermediate list:

private Update BuildMetaData(MetaData[] nvPairs)
{
        Update update = new Update();
        var ip = from nv in nvPairs
                 select new InputProperty()
                 {
                     Name = "udf:" + nv.Name,
                     Val = nv.Value
                 };
        update.Items = ip.ToArray();
        return update;
}
Photocathode answered 25/3, 2009 at 19:40 Comment(1)
you forget to check if nv is nullJiggerypokery
I
2

Use Array.CreateInstance to create an array dynamically.

    private Update BuildMetaData(MetaData[] nvPairs)
    {
        Update update = new Update();
        InputProperty[] ip = Array.CreateInstance(typeof(InputProperty), nvPairs.Count()) as InputProperty[];
        int i;
        for (i = 0; i < nvPairs.Length; i++)
        {
            if (nvPairs[i] == null) break;
            ip[i] = new InputProperty();
            ip[i].Name = "udf:" + nvPairs[i].Name;
            ip[i].Val = nvPairs[i].Value;
        }
        update.Items = ip;
        return update;
    }
It answered 23/8, 2012 at 20:39 Comment(0)
S
0

Typically, arrays require constants to initialize their size. You could sweep over nvPairs once to get the length, then "dynamically" create an array using a variable for length like this.

InputProperty[] ip = (InputProperty[])Array.CreateInstance(typeof(InputProperty), length);

I wouldn't recommend it, though. Just stick with the

List<InputProperty> ip = ...
...
update.Items = ip.ToArray();

solution. It's not that much less performant, and way better looking.

Sciatic answered 25/3, 2009 at 20:6 Comment(0)
G
0

You can create an array dynamically in this way:

 static void Main()
    {
        // Create a string array 2 elements in length:
        int arrayLength = 2;
        Array dynamicArray = Array.CreateInstance(typeof(int), arrayLength);
        dynamicArray.SetValue(234, 0);                              //  → a[0] = 234;
        dynamicArray.SetValue(444, 1);                              //  → a[1] = 444;
        int number = (int)dynamicArray.GetValue(0);                      //  → number = a[0];


        int[] cSharpArray = (int[])dynamicArray;
        int s2 = cSharpArray[0];

    }
Gizela answered 20/12, 2012 at 20:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.