views:

100

answers:

7

Given this example:

 // Create an arary of car objects.      
     car[] arrayOfCars= new car[]
     {
        new car("Ford",1992),
        new car("Fiat",1988),
        new car("Buick",1932),
        new car("Ford",1932),
        new car("Dodge",1999),
        new car("Honda",1977)
     };

I tried something like this:

for (int i = 0; i < dtable.Rows.Count; i++)
{
    DataRow drow = dtable.Rows[i];
    arrayOfCars[] =  new car(drow["make"].ToString(), drow["year"].ToString());
}

How do I add additional data to the array while looping through a datatable?

UPDATE1:

I went with the solution proposed by @Reed.

// Create the array, specifying the total length 
car[] arrayOfCars = new car[dtable.Rows.Count]; 

for (int i = 0; i < dtable.Rows.Count; i++) 
{ 
    DataRow drow = dtable.Rows[i]; 
    // Assign each car to the specific index within the array (arrayOfCars[i]) 
    arrayOfCars[i] =  new car(drow["make"].ToString(), drow["year"].ToString()); 
} 
+10  A: 

You can't add elements to an array once it's been created. Instead of using an array, use a List<car>. This will let you call .Add to add elements.

For example:

 // Create an List of car objects.      
 List<car> listOfCars = new List<car>()
 {
    new car("Ford",1992),
    new car("Fiat",1988),
    new car("Buick",1932),
    new car("Ford",1932),
    new car("Dodge",1999),
    new car("Honda",1977)
 };

You can then do:

for (int i = 0; i < dtable.Rows.Count; i++)
{
    DataRow drow = dtable.Rows[i];
    listOfCars.Add(new car(drow["make"].ToString(), drow["year"].ToString()));
}

You can use the listOfCars like you would use an array, and access elements by index:

car myCar = listOfCars[3];

If you must have an array, create it after you are done "adding to the list" by calling ToArray() on the list:

// ... Add as above...
car[] arrayOfCars = listOfCars.ToArray(); // Creates an array from your list

Edit:

If you are just trying to allocate and construct your array from your DataTable, and are not going to need to add elements to it after it's constructed, you can use an array, like so:

// Create the array, specifying the total length
car[] arrayOfCars = new car[dtable.Rows.Count];

for (int i = 0; i < dtable.Rows.Count; i++)
{
    DataRow drow = dtable.Rows[i];
    // Assign each car to the specific index within the array (arrayOfCars[i])
    arrayOfCars[i] =  new car(drow["make"].ToString(), drow["year"].ToString());
}
Reed Copsey
But he seems to know the number of array items in advance, so why not initialize an array with the correct size? I believe the confusion comes from him trying to use array initializer syntax to insert items into an array.
dtb
@dtb: Does he? It wasn't clear from the question whether he's building the array completely from the DataTable, or building it manually, then adding to it from a DataTable, potentially at a later time or in a separate method...
Reed Copsey
That's a good point dtb, he is using a DataTable so unless he did something crazy you should have a fixed size. Of course from reading this example I'm not sure he is too worried about speed.
Matthew Whited
Reed Copsey
Thanks all - Using the datatable size is much too obvious...
John M
+2  A: 

Arrays cannot be resized in-place.

Instead, you should use a List<Car> and call Add, like this:

 List<car> cars= new List<car>()
 {
    new car("Ford",1992),
    new car("Fiat",1988),
    new car("Buick",1932),
    new car("Ford",1932),
    new car("Dodge",1999),
    new car("Honda",1977)
 };  //C# 3 collection initializer

for (int i = 0; i < dtable.Rows.Count; i++)
{
    DataRow drow = dtable.Rows[i];
    cars.Add(new car((string)drow["make"], (int)drow["year"]));
}
SLaks
`System.Array.Resize<...>(...)`
Matthew Whited
@Matthew Whited: Array.Resize<T> essentially creates a new array, copies all items from the old array and returns the new array. It doesn't actually resize the old array. List<T> encapsulates an array that is resized if needed so you don't have to resize the array yourself (and keep track of the actual number of items etc.)
dtb
My point is that you can resize an array.
Matthew Whited
@Matthew, and the next point would be that you wouldn't want to resize an array with each iteration of a loop. So either (a) use a list or (b) create the appropriate size before the loop. The fact that you can get a resized array is not particularly relevant to this problem.
Anthony Pegram
http://msdn.microsoft.com/en-us/library/bb348051.aspx (I guess I should note that it requires the reference of the array so you can replace the contents).
Matthew Whited
@Anthony, I do not disagee with that at all.
Matthew Whited
@Matthew Whited: From the link you posted: "This method allocates a new array with the specified size, copies elements from the old array to the new one, and then replaces the old array with the new one." It *does not* resize the array.
dtb
@dtb, you got me there. So the particular instance of the array is not resized, but from the standpoint of the reference/value it is.
Matthew Whited
@Matthew, All semantics aside, Array.Resize is an excellent option. Looking into Reflector, it's pretty obvious that a IEnumerable<T>().ToArray() essentially makes the same Array.Copy() call that Array.Resize() makes.
code4life
+1  A: 

I'd only recommend using an array if you know how many elements you'll have in there total. Otherwise you are better off with a List as Reed and SLaks have suggested.

Abe Miessler
+1  A: 

As said above - use List<Car> to have a list with a dynamic amount of elements - use the method Add(Car item) to add new instances. Make sure to visit the appropriate MSDN site: http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx

By the way: The operator [] does not work in C#, even if you created an array with e.g. 5 elements and wanted to add the first one.

Marius Schulz
+3  A: 

Once an array has been created, no new elements can be added. However, you can reassign the elements within it to new objects. If you want new elements (so that your array grows) use (as has been mentioned) the Generic: List<T>. If you want to reassign already existing elements use something like the following (I haven't compiled this, so you may need to make changes:)

for(int i = 0; i < dtable.Rows.Count; i++)
{
    DataRow drow = dtable.Rows[i];
    cars[i] = new car(drow["make"].ToString(), drow["model"].ToString());
}
AllenG
+2  A: 

You could also use LINQ to do this...

var fromTable = from row in dtable.Rows.OfType<DataRow>()
                let make = row["make"] as string
                let year = (int)row["year"]
                select new car(make, year);

car[] arrayOfCars = listOfCars.Concat(fromTable).ToArray();

... If there are tons of Rows in the DataTable and you want to try to squeeze out some performance you could do this instead ...

var makeIndex = dtable.Columns["make"].Ordinal;
var yearIndex = dtable.Columns["year"].Ordinal;

var fromTable = from row in dtable.Rows.OfType<DataRow>()
                let items = row.ItemArray
                let make = items[makeIndex] as string
                let year = (int)items[yearIndex]
                select new car(make, year);
Matthew Whited
+1  A: 

If you have .NET 3.5, then use Array.Resize().

// Create an arary of car objects.      
     car[] arrayOfCars= new car[]
     {
        new car("Ford",1992),
        new car("Fiat",1988),
        new car("Buick",1932),
        new car("Ford",1932),
        new car("Dodge",1999),
        new car("Honda",1977)
     };    

// resize the array...
var rowCount = dtable.Rows.Count;
var offSet = arrayOfCars.Length;
Array.Resize<car>(ref arrayOfCars, rowCount + offSet);

// populate the new (empty) array elements from the database...
for (int i = 0; i < rowCount; i++)
{
    DataRow drow = dtable.Rows[i];
    arrayOfCars[i + offSet] =  
      new car(drow["make"].ToString(), drow["year"].ToString());
}
code4life
I like your approach. The expansion is of a fixed size so this is one of the best answers. The `List<...>` versions work, but depending on the size of the DataTable that could cause several expansions of the internal array. But this is all details that probably won't mean nearly as much to performance as the impact of pulling the column values by the string index name. So I agree the semantics of the issue are rather pointless (but fun to fight about :o)
Matthew Whited