Array
An Array is a fixed-size collection of elements of the same type. It is part of the System namespace. Arrays are useful when you know the number of elements in advance and do not require resizing.
Key Features of an Array
Fixed Size: Size is determined at creation and cannot be changed.
Type-Safe: All elements must be of the same type.
Fast Access: Directly access elements using an index.
Best Use Case: When the number of elements is fixed or known beforehand.
Example of an Array
using System;
class Program
{
static void Main()
{
int[] numbers = new int[5] { 1, 2, 3, 4, 5 };
Console.WriteLine($"First element: {numbers[0]}");
numbers[0] = 10;
Console.WriteLine("\\nArray Elements:");
foreach (var num in numbers)
{
Console.WriteLine(num);
}
}
}
Output:
First element: 1
Array Elements:
10
2
3
4
5
ArrayList
An ArrayList is a dynamically resizable, non-generic collection in the System.Collections namespace. It can store elements of different types. However, since it is non-generic, type safety is not enforced.
Key Features of an ArrayList
Dynamic Resizing: Automatically grows as new elements are added.
Type-Unsafe: Can store objects of any type, leading to potential runtime errors.
Slower than Array: Performance is slightly slower because of boxing/unboxing for value types.
Best Use Case: When you need a dynamic collection and are using .NET versions older than 2.0 (otherwise, prefer List<T>).
Example of an ArrayList
using System;
using System.Collections;
class Program
{
static void Main()
{
ArrayList list = new ArrayList();
list.Add(1);
list.Add("Two");
list.Add(3.0);
Console.WriteLine($"First element: {list[0]}");
Console.WriteLine("\\nArrayList Elements:");
foreach (var item in list)
{
Console.WriteLine(item);
}
list.Remove("Two");
Console.WriteLine("\\nAfter Removal:");
foreach (var item in list)
{
Console.WriteLine(item);
}
}
}
Output:
First element: 1
ArrayList Elements:
1
Two
3
After Removal:
1
3
Comparison of Array vs ArrayList
| Feature | Array | ArrayList |
| Type-Safe | Yes, only one type of elements | No, stores elements as object |
| Resizable | No, fixed size | Yes, dynamic resizing |
| Performance | Faster | Slower due to boxing/unboxing |
| Namespace | System | System.Collections |
| Best Alternative | Fixed data collection | Use List<T> for type safety |
When to Use Which?
Use Array:
Use ArrayList:
For modern applications, List<T> is usually preferred over ArrayList.
HashTable
The Hashtable class in C# is part of the System.Collections namespace and represents a collection of key-value pairs. It is non-generic, meaning it can store keys and values of any data type, and provides fast lookup, insertion, and deletion operations. However, since it's not type-safe, it's less commonly used in modern C# applications where the Dictionary<TKey, TValue> class (which is generic) is preferred for better performance and type safety.
Key Features of Hashtable
Non-Generic: Stores objects of any type (not type-safe).
Key-Value Pairs: It stores data as key-value pairs, where the key is unique.
Hashing: Uses a hash function to determine the index of elements for fast access.
Thread-Safety: Not thread-safe by default. For thread-safety, use Hashtable.Synchronized.
Best Use Case: When you need to store key-value pairs but don't care about type safety (though Dictionary<TKey, TValue> is a better alternative).
Basic Operations with Hashtable
Add: Adds a key-value pair to the Hashtable.
ContainsKey: Checks if a particular key exists.
Remove: Removes a key-value pair.
Indexer: Allows access to values based on keys.
Example of Hashtable
using System;
using System.Collections;
class Program
{
static void Main()
{
Hashtable ht = new Hashtable();
ht.Add(1, "Apple");
ht.Add(2, "Banana");
ht.Add(3, "Cherry");
Console.WriteLine($"Key 1: {ht[1]}");
Console.WriteLine($"Contains key 2: {ht.ContainsKey(2)}");
ht.Remove(2);
Console.WriteLine("\\nHashtable Contents:");
foreach (DictionaryEntry entry in ht)
{
Console.WriteLine($"Key: {entry.Key}, Value: {entry.Value}");
}
}
}
Output:
Key 1: Apple
Contains key 2: True
Hashtable Contents:
Key: 1, Value: Apple
Key: 3, Value: Cherry
Important Methods and Properties
Add(key, value): Adds a key-value pair.
ContainsKey(key): Returns true if the key exists.
ContainsValue(value): Returns true if the value exists.
Remove(key): Removes the entry with the specified key.
Clear(): Removes all key-value pairs from the Hashtable.
Count: Returns the number of key-value pairs in the Hashtable.
Item[key]: Allows access to the value associated with the specified key.
When to Use Hashtable
Legacy Code: If you are maintaining or working with older code that uses Hashtable.
Type Safety Not Important: When type safety is not required and flexibility with key and value types is needed.
Thread-Safety: If you need thread-safe operations, you can use Hashtable.Synchronized.
However, for modern applications, Dictionary<TKey, TValue> is usually the better choice because it's type-safe, faster, and more flexible.
Hashtable vs Dictionary<TKey, TValue>
| Feature | Hashtable | Dictionary<TKey, TValue> |
| Type-Safe | No | Yes |
| Performance | Slightly slower (due to boxing/unboxing) | Faster (type-safe) |
| Thread-Safety | Not thread-safe by default, can use Synchronized | Not thread-safe by default, can use ConcurrentDictionary |
| Generic Support | No | Yes |
| Use Case | Legacy code, untyped collections | Modern, type-safe collections |
Conclusion
Use Hashtable when working with older code or when you need flexibility with different data types (but keep in mind it's not type-safe).
Use Dictionary<TKey, TValue> for modern, type-safe, and high-performance code.
Hashtable Example with More Operations
using System;
using System.Collections;
class Program
{
static void Main()
{
Hashtable ht = new Hashtable();
ht.Add("1", "Apple");
ht.Add("2", "Banana");
ht.Add("3", "Cherry");
ht.Add("4", "Date");
ht.Add("5", "Elderberry");
Console.WriteLine($"Hashtable contains {ht.Count} items.");
Console.WriteLine($"Element with key '3': {ht["3"]}");
Console.WriteLine($"Contains key '2': {ht.ContainsKey("2")}");
Console.WriteLine($"Contains value 'Banana': {ht.ContainsValue("Banana")}");
ht.Remove("4");
Console.WriteLine("\\nRemoved key '4'. Now the Hashtable contains:");
foreach (DictionaryEntry entry in ht)
{
Console.WriteLine($"Key: {entry.Key}, Value: {entry.Value}");
}
try
{
Console.WriteLine($"Element with key '10': {ht["10"]}");
}
catch (KeyNotFoundException ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
ht["1"] = "Avocado";
Console.WriteLine("\\nUpdated element with key '1':");
Console.WriteLine($"Key: 1, New Value: {ht["1"]}");
ht.Clear();
Console.WriteLine($"\\nHashtable cleared. Now it contains {ht.Count} items.");
}
}
Explanation of Operations in the Code
Creating the Hashtable:
Hashtable ht = new Hashtable();
This initializes an empty Hashtable.
Adding Elements:
ht.Add("1", "Apple");
ht.Add("2", "Banana");
Adds key-value pairs to the Hashtable.
Accessing Elements:
Console.WriteLine($"Element with key '3': {ht["3"]}");
Retrieves the value associated with the specified key ("3" in this case).
Checking if Key/Value Exists:
Console.WriteLine($"Contains key '2': {ht.ContainsKey("2")}");
Console.WriteLine($"Contains value 'Banana': {ht.ContainsValue("Banana")}");
These check if the Hashtable contains a particular key or value.
Removing an Element:
ht.Remove("4");
Removes the key-value pair with the specified key ("4" in this case).
Iterating Over the Hashtable:
foreach (DictionaryEntry entry in ht)
{
Console.WriteLine($"Key: {entry.Key}, Value: {entry.Value}");
}
Iterates over all key-value pairs in the Hashtable.
Handling Missing Keys:
try
{
Console.WriteLine($"Element with key '10': {ht["10"]}");
}
catch (KeyNotFoundException ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
Accessing a key that does not exist throws a KeyNotFoundException, which we catch and display a message.
Updating an Element:
ht["1"] = "Avocado";
The value associated with an existing key can be updated using the indexer.
Clearing the Hashtable:
ht.Clear();
Removes all key-value pairs from the Hashtable.
Expected Output
Hashtable contains 5 items.
Element with key '3': Cherry
Contains key '2': True
Contains value 'Banana': True
Removed key '4'. Now the Hashtable contains:
Key: 1, Value: Apple
Key: 2, Value: Banana
Key: 3, Value: Cherry
Key: 5, Value: Elderberry
Error: Key not found.
Updated element with key '1':
Key: 1, New Value: Avocado
Hashtable cleared. Now it contains 0 items.
Summary of Key Points
Add: Adds a key-value pair.
ContainsKey / ContainsValue: Checks if a key or value exists.
Remove: Removes a key-value pair by key.
Iteration: Can be done using a foreach loop over DictionaryEntry.
Indexer ([]): Accesses and modifies values associated with a key.
Clear: Clears all elements in the Hashtable.
BitArray class
The BitArray class in C# is part of the System.Collections namespace and represents a collection of bits (binary values, 0 or 1). It's useful when you need to efficiently store and manipulate a large number of boolean values or binary data. Each element of a BitArray is a single bit, so it provides a memory-efficient way to handle binary data.
Key Features of BitArray
Memory Efficiency: It uses a single bit per element, making it more memory-efficient than using other collections like bool[].
Indexable: You can access and modify individual bits using an index.
Bitwise Operations: It supports bitwise logical operations such as AND, OR, XOR, and NOT.
Fixed Size: Once created, the size of a BitArray is fixed, but you can resize it if needed.
Automatic Resizing: You can increase the size of the BitArray, but it does not shrink automatically.
Thread-Safety: It is not thread-safe by default.
Basic Operations with BitArray
Set: Set a specific bit to true or false.
Get: Get the value of a bit (either true or false).
AND, OR, XOR: Perform bitwise operations.
Count: Get the number of bits in the BitArray.
Example of BitArray Usage
Here's a simple example demonstrating how to create and manipulate a BitArray in C#:
using System;
using System.Collections;
class Program
{
static void Main()
{
BitArray bits = new BitArray(5);
bits[0] = true;
bits[1] = true;
Console.WriteLine("BitArray after setting bits:");
for (int i = 0; i < bits.Length; i++)
{
Console.Write(bits[i] ? "1 " : "0 ");
}
Console.WriteLine();
BitArray otherBits = new BitArray(new bool[] { true, false, true, false, true });
BitArray andResult = bits.And(otherBits);
Console.WriteLine("Result of AND operation:");
for (int i = 0; i < andResult.Length; i++)
{
Console.Write(andResult[i] ? "1 " : "0 ");
}
Console.WriteLine();
BitArray orResult = bits.Or(otherBits);
Console.WriteLine("Result of OR operation:");
for (int i = 0; i < orResult.Length; i++)
{
Console.Write(orResult[i] ? "1 " : "0 ");
}
Console.WriteLine();
BitArray xorResult = bits.Xor(otherBits);
Console.WriteLine("Result of XOR operation:");
for (int i = 0; i < xorResult.Length; i++)
{
Console.Write(xorResult[i] ? "1 " : "0 ");
}
Console.WriteLine();
BitArray notResult = bits.Not();
Console.WriteLine("Result of NOT operation:");
for (int i = 0; i < notResult.Length; i++)
{
Console.Write(notResult[i] ? "1 " : "0 ");
}
Console.WriteLine();
}
}
Explanation of Operations
Creating a BitArray:
A BitArray is created with 5 elements. Initially, all bits are false (0).
BitArray bits = new BitArray(5);
Setting Bits:
Displaying the BitArray:
- A loop is used to print the bits in the array, displaying
1 or 0.
Bitwise Operations:
AND: The And method performs a bitwise AND operation between two BitArray objects.
OR: The Or method performs a bitwise OR operation.
XOR: The Xor method performs a bitwise XOR operation.
NOT: The Not method flips all the bits in the BitArray.
Output of Bitwise Operations:
- Each operation modifies the bits and the result is displayed.
Expected Output
BitArray after setting bits:
1 1 0 0 0
Result of AND operation:
1 0 0 0 0
Result of OR operation:
1 1 1 0 1
Result of XOR operation:
0 1 1 0 1
Result of NOT operation:
0 0 1 1 1
Key Methods of BitArray
And(BitArray value): Performs a bitwise AND between the current BitArray and another BitArray.
Or(BitArray value): Performs a bitwise OR between the current BitArray and another BitArray.
Xor(BitArray value): Performs a bitwise XOR between the current BitArray and another BitArray.
Not(): Flips all the bits in the BitArray.
Length: Gets the number of bits in the BitArray.
Set(int index, bool value): Sets the bit at the specified index to a specified value (true or false).
Get(int index): Retrieves the value of the bit at the specified index.
When to Use BitArray
Memory Efficiency: When you need to work with a large number of boolean values and memory efficiency is important.
Bitwise Operations: If you need to perform bitwise logical operations on collections of bits (such as in networking, compression algorithms, or cryptography).
Flag Management: When dealing with flags or binary options (e.g., checking permissions).
SortedList
The SortedList<TKey, TValue> class in C# is part of the System.Collections.Generic namespace. It represents a collection of key/value pairs that are sorted by the keys and allows fast retrieval based on the key. It is similar to a Dictionary<TKey, TValue>, but with the added feature that the keys are automatically sorted in ascending order.
Key Features of SortedList<TKey, TValue>
Sorted by Keys: The collection is sorted by the keys. This is useful when you need to maintain an ordered collection of items.
Efficient Lookup: SortedList provides fast lookup, similar to a Dictionary, but with the benefit of automatic ordering of keys.
Index Access: You can access both the key-value pairs and individual elements by their index, not just by key.
Performance: Insertions, deletions, and lookups are fast but not as fast as a Dictionary. The insertion might take longer due to the need to maintain the order.
Basic Operations with SortedList<TKey, TValue>
Add: Add a key-value pair to the list.
Get/Set: Retrieve or modify the value associated with a specific key.
Remove: Remove a key-value pair by key.
Index Access: Access items using an index or a key.
Example of SortedList<TKey, TValue> Usage
Here's a simple example demonstrating how to create and manipulate a SortedList:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
SortedList<int, string> sortedList = new SortedList<int, string>();
sortedList.Add(3, "Three");
sortedList.Add(1, "One");
sortedList.Add(2, "Two");
Console.WriteLine("SortedList contents:");
foreach (var kvp in sortedList)
{
Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}");
}
Console.WriteLine("\\nValue for key 2: " + sortedList[2]);
sortedList[2] = "Updated Two";
Console.WriteLine("\\nUpdated value for key 2: " + sortedList[2]);
sortedList.Remove(1);
Console.WriteLine("\\nAfter removing key 1:");
foreach (var kvp in sortedList)
{
Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}");
}
if (sortedList.ContainsKey(3))
{
Console.WriteLine("\\nKey 3 exists in the SortedList.");
}
Console.WriteLine("\\nElement at index 0:");
var elementAtIndex = sortedList.ElementAt(0);
Console.WriteLine($"Key: {elementAtIndex.Key}, Value: {elementAtIndex.Value}");
}
}
Explanation of Operations
Creating a SortedList:
A SortedList<int, string> is created to store integer keys and string values.
SortedList<int, string> sortedList = new SortedList<int, string>();
Adding Elements:
Displaying the SortedList:
- A
foreach loop is used to display all elements, and the list will automatically be sorted by key.
Accessing by Key:
- The value associated with a specific key is accessed directly using
sortedList[key].
Modifying Values:
- You can modify the value for a given key using the indexer (
sortedList[key] = newValue).
Removing Elements:
Checking for Key Existence:
- The
ContainsKey method checks if a specific key exists in the list.
Accessing by Index:
- The
ElementAt(index) method is used to get the element at a particular index in the sorted list.
Expected Output
SortedList contents:
Key: 1, Value: One
Key: 2, Value: Two
Key: 3, Value: Three
Value for key 2: Two
Updated value for key 2: Updated Two
After removing key 1:
Key: 2, Value: Updated Two
Key: 3, Value: Three
Key 3 exists in the SortedList.
Element at index 0:
Key: 2, Value: Updated Two
Key Methods of SortedList<TKey, TValue>
Add(TKey key, TValue value): Adds a key-value pair to the list.
Remove(TKey key): Removes the key-value pair with the specified key.
ContainsKey(TKey key): Checks if a key exists in the list.
ContainsValue(TValue value): Checks if a value exists in the list.
Item[TKey key]: Indexer to get or set a value by key.
Count: Gets the number of key-value pairs in the list.
Keys: Gets a collection of the keys in the list.
Values: Gets a collection of the values in the list.
When to Use SortedList<TKey, TValue>
Ordered Collection: When you need to maintain a collection of items that are always sorted by key.
Fast Lookup: If you need to look up values by key in an ordered collection with a small overhead on insertions and deletions.
Efficient for Smaller Collections: While SortedList is efficient in terms of sorting and lookups, it may not be as efficient as Dictionary for larger collections because of the overhead required to maintain sorting.