Friday, March 25, 2011

ArrayList and Array


This tutorial is divided into the following sections:
  • Arrays in General
  • Declaring Arrays
  • Initializing Arrays
  • Accessing Array Members
  • Arrays are Objects
  • Using foreach with Arrays

Arrays in General

C# arrays are zero indexed; that is, the array indexes start at zero. Arrays in C# work similarly to how arrays work in most other popular languages There are, however, a few differences that you should be aware of.
When declaring an array, the square brackets ([]) must come after the type, not the identifier. Placing the brackets after the identifier is not legal syntax in C#.

int[] table; // not int table[];  
Another detail is that the size of the array is not part of its type as it is in the C language. This allows you to declare an array and assign any array of int objects to it, regardless of the array's length.

int[] numbers; // declare numbers as an int array of any size
numbers = new int[10];  // numbers is a 10-element array
numbers = new int[20];  // now it's a 20-element array

Declaring Arrays

C# supports single-dimensional arrays, multidimensional arrays (rectangular arrays), and array-of-arrays (jagged arrays). The following examples show how to declare different kinds of arrays:
Single-dimensional arrays:

int[] numbers;
Multidimensional arrays:

string[,] names;
Array-of-arrays (jagged):

byte[][] scores;
Declaring them (as shown above) does not actually create the arrays. In C#, arrays are objects (discussed later in this tutorial) and must be instantiated. The following examples show how to create arrays:
Single-dimensional arrays:

int[] numbers = new int[5];
Multidimensional arrays:

string[,] names = new string[5,4];
Array-of-arrays (jagged):

byte[][] scores = new byte[5][];
for (int x = 0; x < scores.Length; x++) 
{
   scores[x] = new byte[4];
}
You can also have larger arrays. For example, you can have a three-dimensional rectangular array:

int[,,] buttons = new int[4,5,3];
You can even mix rectangular and jagged arrays. For example, the following code declares a single-dimensional array of three-dimensional arrays of two-dimensional arrays of type int:

int[][,,][,] numbers;

Example

The following is a complete C# program that declares and instantiates arrays as discussed above.

// arrays.cs
using System;
class DeclareArraysSample
{
    public static void Main()
    {
        // Single-dimensional array
        int[] numbers = new int[5];

        // Multidimensional array
        string[,] names = new string[5,4];

        // Array-of-arrays (jagged array)
        byte[][] scores = new byte[5][];

        // Create the jagged array
        for (int i = 0; i < scores.Length; i++)
        {
            scores[i] = new byte[i+3];
        }

        // Print length of each row
        for (int i = 0; i < scores.Length; i++)
        {
            Console.WriteLine("Length of row {0} is {1}", i, scores[i].Length);
        }
    }
}

Output


Length of row 0 is 3
Length of row 1 is 4
Length of row 2 is 5
Length of row 3 is 6
Length of row 4 is 7

Initializing Arrays

C# provides simple and straightforward ways to initialize arrays at declaration time by enclosing the initial values in curly braces ({}). The following examples show different ways to initialize different kinds of arrays.
Note   If you do not initialize an array at the time of declaration, the array members are automatically initialized to the default initial value for the array type. Also, if you declare the array as a field of a type, it will be set to the default value null when you instantiate the type.

Single-Dimensional Array


int[] numbers = new int[5] {1, 2, 3, 4, 5};
string[] names = new string[3] {"Matt", "Joanne", "Robert"};
You can omit the size of the array, like this:

int[] numbers = new int[] {1, 2, 3, 4, 5};
string[] names = new string[] {"Matt", "Joanne", "Robert"};
You can also omit the new operator if an initializer is provided, like this:

int[] numbers = {1, 2, 3, 4, 5};
string[] names = {"Matt", "Joanne", "Robert"};

Multidimensional Array


int[,] numbers = new int[3, 2] { {1, 2}, {3, 4}, {5, 6} };
string[,] siblings = new string[2, 2] { {"Mike","Amy"}, {"Mary","Albert"} };
You can omit the size of the array, like this:

int[,] numbers = new int[,] { {1, 2}, {3, 4}, {5, 6} };
string[,] siblings = new string[,] { {"Mike","Amy"}, {"Mary","Albert"} };
You can also omit the new operator if an initializer is provided, like this:

int[,] numbers = { {1, 2}, {3, 4}, {5, 6} };
string[,] siblings = { {"Mike", "Amy"}, {"Mary", "Albert"} };

Jagged Array (Array-of-Arrays)

You can initialize jagged arrays like this example:

int[][] numbers = new int[2][] { new int[] {2,3,4}, new int[] {5,6,7,8,9} };
You can also omit the size of the first array, like this:

int[][] numbers = new int[][] { new int[] {2,3,4}, new int[] {5,6,7,8,9} };
-or-

int[][] numbers = { new int[] {2,3,4}, new int[] {5,6,7,8,9} };
Notice that there is no initialization syntax for the elements of a jagged array.

Accessing Array Members

Accessing array members is straightforward and similar to how you access array members in C/C++. For example, the following code creates an array called numbers and then assigns a 5 to the fifth element of the array:

int[] numbers = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
numbers[4] = 5;
The following code declares a multidimensional array and assigns 5 to the member located at [1, 1]:

int[,] numbers = { {1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10} };
numbers[1, 1] = 5;
The following is a declaration of a single-dimension jagged array that contains two elements. The first element is an array of two integers, and the second is an array of three integers:

int[][] numbers = new int[][] { new int[] {1, 2}, new int[] {3, 4, 5}
};
The following statements assign 58 to the first element of the first array and 667 to the second element of the second array:

numbers[0][0] = 58;
numbers[1][1] = 667;

Arrays are Objects

In C#, arrays are actually objects. System.Array is the abstract base type of all array types. You can use the properties, and other class members, that System.Array has. An example of this would be using the Length property to get the length of an array. The following code assigns the length of thenumbers array, which is 5, to a variable called LengthOfNumbers:

int[] numbers = {1, 2, 3, 4, 5};
int LengthOfNumbers = numbers.Length;
The System.Array class provides many other useful methods/properties, such as methods for sorting, searching, and copying arrays.

Using foreach on Arrays

C# also provides the foreach statement. This statement provides a simple, clean way to iterate through the elements of an array. For example, the following code creates an array called numbers and iterates through it with the foreach statement:

int[] numbers = {4, 5, 6, 1, 2, 3, -2, -1, 0};
foreach (int i in numbers)
{
   System.Console.WriteLine(i);
}
With multidimensional arrays, you can use the same method to iterate through the elements, for example:

int[,] numbers = new int[3, 2] {{9, 99}, {3, 33}, {5, 55}};
foreach(int i in numbers)
{
   Console.Write("{0} ", i);
}
The output of this example is:

9 99 3 33 5 55
However, with multidimensional arrays, using a nested for loop gives you more control over the array elements.


You need to use the ArrayList class in an older C# program to fix or improve the dynamic arrays. ArrayList is still useful, even when newer classes are more durable and popular. Here we see examples and tips using the ArrayList class in the C# programming language, moving from the simpler tasks to the more advanced usages of ArrayList.

Adding elements

The Add method on ArrayList is used in almost every program. It appends a new element object to the very end of the ArrayList. You can keep adding elements to your collection until memory runs out. The objects are stored in the managed heap.
=== Program that uses ArrayList (C#) ===

using System.Collections;

class Program
{
    static void Main()
    {
        //
        // Create an ArrayList and add three elements.
        //
        ArrayList list = new ArrayList();
        list.Add("One");
        list.Add("Two");
        list.Add("Three");
    }
}

=== Result of the program ===
    An ArrayList with three elements is created.
What the example shows. First, this is a complete console program that you can run in the Visual Studio IDE. When you run this example, there will be three elements added to the ArrayList. The first element is a string containing "One". The last element is "Three".

Using ArrayList in methods

Structural programming with ArrayList is easy, as you can simply pass the object with the ArrayList type. However, in the receiving function, you have to know (or find out) what the type of each element is. Here we pass the ArrayList as a parameter.
=== Program that uses ArrayList parameter (C#) ===

using System;
using System.Collections;

class Program
{
    static void Main()
    {
        //
        // Create an ArrayList and add two ints.
        //
        ArrayList list = new ArrayList();
        list.Add(5);
        list.Add(7);
        //
        // Use ArrayList with method.
        //
        Example(list);
    }

    static void Example(ArrayList list)
    {
        foreach (int i in list)
        {
            Console.WriteLine(i);
        }
    }
}

=== Output of the program ===

5
7
Note on using ArrayList as return value. You can also use the ArrayList as a return value. Use the ArrayList type as the return keyword at the start of your method. Note that generally it is best to reuse the same ArrayList instead of combining more than one.

Adding one ArrayList to second one

There are different ways to add one ArrayList to another, but the best way is using AddRange. Internally, AddRange uses the Array.Copy or CopyTo methods, which have better performance than some loops.
=== Program that uses Add and AddRange (C#) ===

using System;
using System.Collections;

class Program
{
    static void Main()
    {
        //
        // Create an ArrayList with two values.
        //
        ArrayList list = new ArrayList();
        list.Add(5);
        list.Add(7);
        //
        // Second ArrayList.
        //
        ArrayList list2 = new ArrayList();
        list2.Add(10);
        list2.Add(13);
        //
        // Add second ArrayList to first.
        //
        list.AddRange(list2);
        //
        // Display the values.
        //
        foreach (int i in list)
        {
            Console.WriteLine(i);
        }
    }
}

=== Output of the program ===

5
7
10
13
Description of the two ArrayLists. The first ArrayList has two elements added to it. Next, the second ArrayList has two elements added to it. The second ArrayList is then appended to the first using the AddRange method. The example finally shows the output.

Using Count and Clear

The ArrayList class provides the Count property, which is a virtual property. When you use Count, no counting is actually done; instead, a cached field value is returned. This means that Count is fairly fast. The example also shows Clear.
=== Program that uses Count (C#) ===

using System;
using System.Collections;

class Program
{
    static void Main()
    {
        //
        // Create an ArrayList with two values.
        //
        ArrayList list = new ArrayList();
        list.Add(9);
        list.Add(10);
        //
        // Show number of elements in ArrayList.
        //
        Console.WriteLine(list.Count);
        //
        // Clear the ArrayList.
        //
        list.Clear();
        //
        // Show count again.
        //
        Console.WriteLine(list.Count);
    }
}

=== Output of the program ===

2
0
Usage of Count. The Count property returns an int, and you can assume this will always be a positive value. Sometimes, you can store the count in a local variable for better performance, but this isn't usually needed because no calculation takes place in the property itself.
Usage of Clear method. You can call the instance method Clear on your ArrayList. Internally, this calls the Array.Clear method. Sometimes, your code is clearer if you create a new ArrayList instead.

Sorting and reversing ArrayList

Many dynamic arrays such as ArrayList must be sorted frequently, before insertion into the output web page or Windows program. This greatly improves the functionality and usability in programs. You can call the instance Sort method on an ArrayList, and then we call Reverse on that sorted collection. These methods work in-place.
Sorting ranges in your ArrayList. You can sort subsets (ranges) of elements in your ArrayList using the third overload. This can be useful for rare situations, but isn't likely to be needed. Additionally, you can Reverse only a range of your ArrayList.

Inserting and removing elements

Here we see how you can insert and remove elements with the Insert and Remove family of methods. Specifically, we see the RemoveAt method for erasing a single element, then the Insert method and RemoveRange methods.
=== Program that uses Insert and Remove (C#) ===

using System;
using System.Collections;

class Program
{
    static void Main()
    {
        //
        // Create an ArrayList with three strings.
        //
        ArrayList list = new ArrayList();
        list.Add("Dot");
        list.Add("Net");
        list.Add("Perls");
        //
        // Remove middle element in ArrayList.
        //
        list.RemoveAt(1); // It becomes [Dot, Perls]
        //
        // Insert word at beginning of ArrayList.
        //
        list.Insert(0, "Carrot"); // It becomes [Carrot, Dot, Perls]
        //
        // Remove first two words from ArrayList.
        //
        list.RemoveRange(0, 2);
        //
        // Display the result ArrayList.
        //
        foreach (string value in list)
        {
            Console.WriteLine(value); // <-- "Perls"
        }
    }
}

=== Output of the program ===

Perls

Looping with 'for'

In C# programming, the for loop is a very popular and useful loop construct. However, when using for on an ArrayList, you will need to cast the element after using its index. The [i] part in the example below demonstrates how to use the indexer on the ArrayList. You can find more separate information on indexers here.
=== Program that uses ArrayList and for (C#) ===

using System;
using System.Collections;

class Program
{
    static void Main()
    {
        //
        // Create an ArrayList with three strings.
        //
        ArrayList list = new ArrayList();
        list.Add("man");
        list.Add("woman");
        list.Add("plant");
        //
        // Loop over ArrayList with for.
        //
        for (int i = 0; i < list.Count; i++)
        {
            string value = list[i] as string;
            Console.WriteLine(value);
        }
    }
}

=== Output of the program ===

man
woman
plant
Using "as" cast with ArrayList elements. The "as" cast in C# is probably the best way to cast reference types such as string. After you cast, you can check the result for null before using the variable, to see if the cast succeeded. This is not always needed.

Getting range of values

Another interesting method you can use is the GetRange method, which will return to you a subset of the original ArrayList in a new ArrayList. This is ideal when you know a certain part of your ArrayList has a different purpose or behavior.
=== Program that uses GetRange (C#) ===

using System;
using System.Collections;

class Program
{
    static void Main()
    {
        //
        // Create an ArrayList with 4 strings.
        //
        ArrayList list = new ArrayList();
        list.Add("fish");
        list.Add("amphibian");
        list.Add("bird");
        list.Add("plant");
        //
        // Get last two elements in ArrayList.
        //
        ArrayList range = list.GetRange(2, 2);
        //
        // Display the elements.
        //
        foreach (string value in range)
        {
            Console.WriteLine(value); // bird, plant
        }
    }
}

=== Output of the program ===

bird
plant
Note on SetRange and RemoveRange. The SetRange method on ArrayList is also useful when you need to replace a range. However, I have not found SetRange to be useful, as often you will just want to replace elements in a for loop.

Understanding IndexOf and LastIndexOf

The IndexOf and LastIndexOf methods on ArrayList are similar to those on strings. You pass in the value you are looking for, the start index, the number of elements to search. IndexOf will return -1 if the element could not be located.

Converting ArrayList to array

Arrays in C# offer more performance and compatibility, so you will want to convert ArrayLists to arrays. Due to the boxing and unboxing requirements with the ArrayList, you need to specify more complex casts than with the List constructed type. This site has more details on converting ArrayLists.

Understanding BinarySearch method

The BinarySearch method on ArrayList implements the binary searching algorithm. This uses a "divide and conquer" approach to finding the correct element, and only works on a pre-sorted array. For this reason, never use BinarySearch if your ArrayList might not be sorted.

Performance and memory usage

There is a significant performance penalty in using ArrayList, particularly on value types. This is because boxing occurs, which is a way the runtime turns a value type into an object. This site has some material on the cost of unboxing.

Should I use List<T> instead?

Yes, assuming the project you are working on is compatible. Older .NET deployed applications may be using ArrayList, and it is often best not to have to rewrite them. Lists not only avoid boxing or unboxing, but they also lead to clearer and less bug-prone code. This is because the compiler can check your code for type integrity before runtime.

Summary

Here we saw how you can use ArrayList in a variety of contexts in the C# language. Generally, ArrayList is best used in legacy programs. The newer .NET runtimes offer better collections in System.Collections.Generic. However, the examples here are practical for you if you are working with an old program or learning from an older book. This article is based on .NET 3.5 SP1.

No comments :

Post a Comment