Collections in C#

 

Collections in C#

In .NET, collections are data structures used to store and manage groups of objects. Collections are broadly categorized into generic and non-generic based on whether they are type-safe (generic) or not (non-generic). Here's a detailed explanation of both:

When to Use Generic vs Non-Generic?

  • Use Generic Collections when:

    • Type safety is required.

    • Performance is a concern.

    • You know the types at compile time.

  • Use Non-Generic Collections when:

    • Working with older .NET versions (pre-2.0).

    • Interacting with APIs or libraries that return non-generic collections.


1. Non-Generic Collections

Non-generic collections are part of the System.Collections namespace. They store objects as System.Object type, meaning they lack type safety. Developers often need to cast the objects to their actual types during retrieval, which can lead to runtime errors.

Common Non-Generic Collections

ArrayList

  • Stores elements as object.

  • Automatically resizes as elements are added or removed.

Example:

ArrayList arrayList = new ArrayList();

arrayList.Add(1);

arrayList.Add("Two");

arrayList.Add(3.5);

// Retrieving requires casting

int first = (int)arrayList[0];

    HashTable

The Hashtable class represents a collection of key-and-value pairs that are organized based on the hash code of the key. It uses the key to access the elements in the collection.

Ex:

  Hashtable ht = new Hashtable();        

         ht.Add("001", "Zara Ali");

         ht.Add("002", "Abida Rehman");

 ICollection key = ht.Keys;        

         foreach (string k in key) {

            Console.WriteLine(k + ": " + ht[k]);        

 }

         Console.ReadKey();


  • ArrayList vs HashTable

1.ArrayList  represents the ordered collection of an object or it can be said that it is individually indexed whereas a Hash table uses a key to access the elements in the collection.

2.ArrayList is used when you want to access the elements by using index whereas Hash table is used when you must access elements by using an index.


Stack

  • Last-In-First-Out (LIFO) collection.

Example:

Stack stack = new Stack();

stack.Push(1);

stack.Push("Two");

var item = stack.Pop(); // Requires casting


  1. Queue

    • First-In-First-Out (FIFO) collection.

Example:

Queue queue = new Queue();

queue.Enqueue(1);

queue.Enqueue("Two");

var item = queue.Dequeue(); // Requires casting


Limitations of Non-Generic Collections

  • Type Safety: They store objects as object, requiring explicit casting when retrieving.

  • Performance: Boxing and unboxing occur when storing and retrieving value types, affecting performance.

  • Error-Prone: Casting may cause runtime errors if the wrong type is used.





2. Generic Collections

Generic collections are part of the System.Collections.Generic namespace. They are type-safe, meaning they work with specific types and eliminate the need for casting.

Advantages of Generic Collections

  • Type Safety: Ensures only the specified type can be stored.

  • Performance: Avoids boxing and unboxing, reducing overhead.

  • Compile-Time Errors: Type mismatches are caught at compile time.

Common Generic Collections

  • List<T>

    • Dynamic array that grows as needed.

    • Type-safe and strongly typed.

Example:
List<int> numbers = new List<int>();

numbers.Add(1);

numbers.Add(2);

int first = numbers[0];

  • Dictionary<TKey, TValue>

    • Key-value pair storage with unique keys.


Dictionary<int, string> dictionary = new Dictionary<int, string>();

dictionary.Add(1, "One");

dictionary.Add(2, "Two");

string value = dictionary[1];





  • Stack<T>

    • Generic LIFO collection.

Example:

Stack<string> stack = new Stack<string>();

stack.Push("First");

stack.Push("Second");

string item = stack.Pop();

  • Queue<T>

    • Generic FIFO collection.

Example:

Queue<double> queue = new Queue<double>();

queue.Enqueue(1.1);

queue.Enqueue(2.2);

double item = queue.Dequeue();

  • HashSet<T>

    • Stores unique elements and prevents duplicates.

Example:

HashSet<int> set = new HashSet<int>();

set.Add(1);

set.Add(2);

set.Add(1); // Duplicate, won't be added





  • SortedList<TKey, TValue>

    • Maintains key-value pairs in sorted order.


SortedList<int, string> sortedList = new SortedList<int, string>();

sortedList.Add(2, "Two");

sortedList.Add(1, "One");


  • SortedList

        SortedList sl = new SortedList();        

         sl.Add("001", "Zara Ali");

         sl.Add("002", "Abida Rehman");


  • Stack


  • BitArray

It represents an array of the binary representation using the values 1 and 0.


String vs StringBuilder

String is immutable and StringBuilder is mutable


Array:

In C#, an array is a collection of elements of the same type stored in contiguous memory locations. It is a fixed-size, strongly typed data structure provided by the language, useful for storing multiple values of the same type.

Key Features of Arrays

  1. Fixed Size: Once an array is created, its size cannot be changed.

  2. Strongly Typed: All elements in the array must be of the same type.

  3. Zero-Based Indexing: Array indices start at 0.

  4. Reference Type: Arrays are reference types in C# and derive from the System.Array class.

  5. Contiguous Memory: Elements are stored in adjacent memory locations.

Declaring and Initializing Arrays

1. Declaration

An array is declared using square brackets ([]):

int[] numbers;    // Declaration of an integer array

2. Initialization

You can initialize an array using:

Size (to define the length):
numbers = new int[5]; // Creates an array of size 5

Values (to directly assign elements):

int[] numbers = { 1, 2, 3, 4, 5 };

Combination

int[] numbers = new int[5] { 1, 2, 3, 4, 5 };

3. Default Values

When an array is initialized, all elements are set to the default value of the array's data type:

  • int0

  • float0.0

  • boolfalse

  • stringnull

Accessing Elements

Use the index to access or modify elements:

int[] numbers = { 10, 20, 30, 40, 50 };

int first = numbers[0];    // Access first element (10)

numbers[1] = 25;           // Modify second element to 25

Important Points

  • Accessing an invalid index throws a System.IndexOutOfRangeException.


Types of Arrays

1. Single-Dimensional Array

A one-dimensional array stores elements in a linear form.

int[] numbers = { 1, 2, 3, 4, 5 };

2. Multi-Dimensional Array

Arrays with more than one dimension.

a. Rectangular Arrays

Each row has the same number of columns.

int[,] matrix = new int[3, 2] { { 1, 2 }, { 3, 4 }, { 5, 6 } };

// Access element at row 1, column 2

int value = matrix[0, 1]; // 2

b. Jagged Arrays

An array of arrays, where each sub-array can have a different size.

var numbers = new[] { 1, 2, 3, 4 }; // Inferred as int[]

3. Implicitly Typed Arrays

Arrays where the type is inferred by the compiler.

var numbers = new[] { 1, 2, 3, 4 }; // Inferred as int[]



Common Operations on Arrays

1. Iterating Over an Array

int[] numbers = { 1, 2, 3, 4, 5 };

// Using for loop

for (int i = 0; i < numbers.Length; i++){    Console.WriteLine(numbers[i]);}

// Using foreach loop

foreach (int number in numbers){

    Console.WriteLine(number);}

2. Sorting

int[] numbers = { 5, 3, 8, 1 };

Array.Sort(numbers);  // Sorts the array in ascending order

3. Searching

int[] numbers = { 1, 2, 3, 4, 5 };

int index = Array.IndexOf(numbers, 3); // Returns the index of the element (2)


4. Copying


int[] numbers = { 1, 2, 3 };

int[] copy = new int[3];

Array.Copy(numbers, copy, numbers.Length);


5. Reversing


int[] numbers = { 1, 2, 3 };

Array.Reverse(numbers); // { 3, 2, 1 }



Advanced Concepts

1. Length and Rank

Length: Total number of elements.

int[] numbers = { 1, 2, 3, 4, 5 };

Console.WriteLine(numbers.Length); // 5


Rank: Number of dimensions.

int[,] matrix = new int[3, 2];

Console.WriteLine(matrix.Rank); // 2


2. Bounds

GetUpperBound: Gets the upper bound of a dimension.

int[,] matrix = new int[3, 2];

int lastRow = matrix.GetUpperBound(0); // 2

int lastCol = matrix.GetUpperBound(1); // 1



Limitations of Arrays

  1. Fixed Size: Cannot grow or shrink dynamically.

  2. Inefficient Insert/Delete: Adding or removing elements is cumbersome.

  3. No Built-In High-Level Operations: Unlike collections like List<T>, arrays lack methods like Add.


When to Use Arrays?

  • Use arrays when:

    • The size of the collection is known and fixed.

    • Performance is critical, as arrays provide faster access than collections like List<T>.

  • Prefer collections (List<T>, Dictionary<TKey, TValue>, etc.) for dynamic or complex data structures.


Example Program

using System;


class Program

{

    static void Main()

    {

        // Single-dimensional array

        int[] numbers = { 10, 20, 30, 40, 50 };


        Console.WriteLine("Array Elements:");

        foreach (int number in numbers)

        {

            Console.WriteLine(number);

        }


        // Multi-dimensional array

        int[,] matrix = {

            { 1, 2, 3 },

            { 4, 5, 6 },

            { 7, 8, 9 }

        };


        Console.WriteLine("\nMatrix Elements:");

        for (int i = 0; i < 3; i++)

        {

            for (int j = 0; j < 3; j++)

            {

                Console.Write(matrix[i, j] + " ");

            }

            Console.WriteLine();

        }

    }

}


Comments

Popular posts from this blog

Performance Optimization in Sitecore

Strategies for Migrating to Sitecore from legacy or upgrading from older Sitecore

Azure Event Grid Sample code