int[] array = new int[2]; // creates array of length 2, default values
string[] array = new string[] { "A", "B" }; // creates populated array of length 2
string[] array = { "A" , "B" }; // creates populated array of length 2
string[] array = new[] { "A", "B" }; // creates populated array of length 2
const int i = 1;
string[] array = new string[i]; // OK only if i is a constant
using System.Linq;
int[] array = Enumerable.Repeat(1, 10).ToArray(); // creates array of length 10 populated with 1
int[] array = Enumerable.Range(1, 10).ToArray(); // creates array from 1 to 10 (included)
int[] array = Enumerable.Range(1, 10).ToArray();
/**** Basic Operations ****/
int length = array.Length; // 10 - Size of array
/**** Access, Slicing, Search and Insertion ****/
int index = 3, indexStart = 2, indexEnd = 5, distanceFromEnd = 2; valSearch = 7, valInsert = 9;
int val = array[index]; // Access - 4
int val = array[^index]; // Access - Access element (array.Length - index) - 7
int[] subArray = array[indexStart..indexEnd]; // Slicing - From indexStart to indexEnd - excluded) - [3, 4, 5]
int[] subArray = array[indexStart..^distanceFromEnd]; // Slicing - From indexStart to index (array.Length - distanceFromEnd) included - [3, 4, 5, 6, 7, 8, 9]
bool b = array.Contains(valSearch); // Contains - Can also use Array.Exists(array, x => x == valSearch) that requires a predicate (slower) - true
int indexOf = Array.IndexOf(array, valSearch); // Search - Returns -1 if not found - 6
array[index] = valInsert; // Insertion - Replace an existing value
/**** Comparison Operations ****/
int min = array.Min(); // 1 - Minimum of array - Note: Faster using for loop
int max = array.Max(); // 10 - Maximum of array - Note: Faster using for loop
/**** Aggregation Operations ****/
int sum = array.Sum(); // 60 - Sum of array
double average = array.Average(); // 6 - Average of array
/**** Sort/Reverse Operations ****/
Array.Sort(array); // Sort the array - 1 2 3 5 6 7 8 9 9 10
Array.Reverse(array); // Reverse the array - 10 9 9 8 7 6 5 3 2 1
/**** Copy Operations ****/
int[] array2 = array; // Copy by reference (change to one modifies other)
int[] array3 = (int[]) array.Clone(); // Copy by value (change to one does not modify other)
/**** Print Operation ****/
Console.WriteLine(String.Join("; ", array)); // 10; 9; 9; 8; 7; 6; 5; 3; 2; 1
string[ , ] marray = new string[2, 3]; // Create an empty array with 2 rows and 3 columns
int[ , ] marray = { { 1, 2, 3 }, { 3, 4, 5 } }; // Create an array with 2 rows and 3 columns
int[ , ] marray = new int[2, 3]{ { 1, 2, 3 }, { 3, 4, 5 } }; // Create an array with 2 rows and 3 columns
int[ , , ] marray = { { { 1, 3, 5 }, { 2, 4, 6 } }, { { 2, 4, 9 }, { 5, 7, 11 } } }; // 3 dimensional array
using System.Linq;
int[ , ] marray = { { 1, 2, 3 }, { 3, 4, 5 } }; // Create an array with 2 rows and 3 columns
/**** Basic Operations ****/
Console.WriteLine(marray.GetLength(0)); // 2 - Number of Rows (1st dimension)
Console.WriteLine(marray.GetLength(1)); // 3 - Number of Columns (2nd dimension)
/**** Extract Columns and Rows ****/
// Get Column of a marray using Linq
public T[] GetColumn(T[,] marray, int columnNumber) {
return Enumerable.Range(0, marray.GetLength(0))
.Select(x => marray[x, columnNumber])
.ToArray();
}
// Get Row of a marray using Linq
public T[] GetRow(T[,] marray, int rowNumber) {
return Enumerable.Range(0, marray.GetLength(1))
.Select(x => marray[rowNumber, x])
.ToArray();
}
A jagged array is an array whose elements are arrays, possibly of different sizes. A jagged array is sometimes called an “array of arrays.”. It can also be used with multi dimensional arrays.
int[][] jaggedArray = new int[3][]; // Create an empty jagged array of 3 arrays of different undefined sizes
jaggedArray[0] = new int[5]; // Set size of first array to 5
jaggedArray[1] = new int[4]; // Set size of second array to 4
jaggedArray[2] = new int[2]; // Set size of third array to 2
int[][] jaggedArray = new int[3][]; // Create an empty jagged array of 3 arrays of different undefined sizes
jaggedArray[0] = new int[] { 1, 3, 5, 7, 9 }; // Define first array
jaggedArray[1] = new int[] { 0, 2, 4, 6 }; // Define second array
jaggedArray[2] = new int[] { 11, 22 }; // Define third array
int[][] jaggedArray = new int[][]
{
new int[] { 1, 3, 5, 7, 9 },
new int[] { 0, 2, 4, 6 },
};
int[][] jaggedArray =
{
new int[] { 1, 3, 5, 7, 9 },
new int[] { 0, 2, 4, 6 },
};
C# List
are Linked List (ie with variable size).
To use List
, you need to import System.Collections.Generic
.
using System.Collections.Generic;
List<int?> list = new List<int?>(); // creates an empty List
List<int?> list = new List<int?>(){null, 2}; // creates populated List of length 2
using System.Linq;
List<int> list = Enumerable.Repeat(1, 10).ToList(); // creates a List of length 10 populated with 1
List<int> list = Enumerable.Range(1, 10).ToList(); // creates List from 1 to 10 (included)
using System.Collections.Generic;
using System.Linq;
List<int> list = Enumerable.Range(1, 10).ToList();
/**** Basic Operations ****/
int length = list.Count; // 10 - Size of List
/**** Access, Slicing, Search, Insertion and Deletion ****/
int index = 3, indexStart = 2, indexEnd = 5, valSearch = 7, valToInsertAdd = 9, valToInsertReplace = 6, nbElements = 4;
int val = list[index]; // Access - 4
List<int> subList = list.GetRange(indexStart, nbElements); // Slicing - nbElements starting at indexStart - [3, 4, 5, 6]
bool b = list.Contains(valSearch); // Contains - true
int indexOf = list.IndexOf(valSearch); // Search - Returns -1 if not found - 6
list.Add(valToInsertAdd); // Insertion - Add a new value
list[index] = valToInsertReplace; // Insertion - Replace an existing value
list.InsertRange(indexStart, subList); // Insertion - Insert the list subList at index indexStart
list.Remove(valSearch); // Remove - Remove first occurence
list.RemoveAt(index); // Remove by index
list.RemoveRange(indexStart, nbElements);// Remove Range - Remove nbElements elements starting at indexStart
/**** Comparison Operations ****/
int min = list.Min(); // 1 - Minimum of List
int max = list.Max(); // 10 - Maximum of List
/**** Aggregation Operations ****/
int sum = list.Sum(); // 56 - Sum of List
double average = list.Average(); // 6.22 - Average of List
/**** Sort/Reverse Operations ****/
list.Sort(); // Sort the list - 1 2 5 6 6 8 9 9 10
list.Reverse(); // Reverse the list - 10 9 9 8 6 6 5 2 1
/**** Copy Operations ****/
/** Shallow Copy **/
List<int> listCopy = new List<int>(list); // For value types List, change to one list does not modify the other (not true for reference types list)
/** Deep Copy **/
List<ReferenceType> listDeepCopy = new List<ReferenceType>(list.Count);
list.ForEach((item) => { listDeepCopy.Add(new ReferenceType(item)); }); // Requires a copy constructor for ReferenceType
/**** Print Operation ****/
Console.WriteLine(String.Join("; ", list)); // 10; 9; 9; 8; 6; 6; 5; 2; 1
To use SortedList
(SortedList<TKey, TValue>
), you need to import System.Collections.Generic
.
SortedList<TKey, TValue>
is a collection class that can store key-value pairs that are sorted by the keys based on the associated IComparer implementation (see Tutorial Teacher on Sorted Lists)
using System.Collections.Generic;
SortedList<int, string> sortedList = new SortedList<int, string>();
sortedList.Add(3, "Three");
sortedList.Add(1, "One");
sortedList.Add(2, "Two");
SortedList<int, string> sortedList = new SortedList<int, string>()
{
{3, "Three"},
{5, "Five"},
{1, "One"}
};
See this Geeks for Geeks page. A Heap is stored as a Binary tree where the parents are always greater (MaxHeap) or lower (MinHeap) than their children. A Heap does not have rules for left and right children (it is not a binary search tree).
Time Complexity comparison between a MinHeap and a SortedList (ascending order):
Operation | SortedList | Heap |
---|---|---|
Insert | O(n) | O(log(n)) |
Search | O(log(n)) | O(n) |
Find Min | O(1) | O(1) |
Delete Min | O(n) | O(log(n)) |
To use HashSet
, you need to import System.Collections.Generic
.
using System.Collections.Generic;
HashSet<int> hashset = new HashSet<int>();
HashSet<int> hashset = new HashSet<int>() { 1, 2, 3 };
using System.Collections.Generic;
using System.Linq;
HashSet<int> hashset = new HashSet<int>() { 1, 2, 3 };
/**** Basic Operations ****/
int size = hashset.Count; // Get number of elements of hashset - Can use .Count()
int val = 4, valAlreadyInHashet = 1;
hashset.Add(val); // Add val to hashset
hashset.Add(valAlreadyInHashet); // If val already in hashset, do Nothing
bool b = hashset.Contains(val); // Check if key already in hashset
/**** Extract Values ****/
int[] arrayValues = hashset.ToArray(); // Requires Systel.Linq
List<int> listValues = hashset.ToList(); // Requires Systel.Linq
/**** Comparison Operations ****/
int min = hashset.Min();
var max = hashset.Max();
/**** Intersection and Union Operations ****/
HashSet<int> hashset2 = new HashSet<int>() { 1, 7, 8, 9 };
HashSet<int> hashsetOutIntersection = hashset.Intersect(hashset2).ToHashSet(); // { 1 } - Requires System.Linq
HashSet<int> hashsetOutUnion = hashset.Union(hashset2).ToHashSet(); // { 1, 2, 3, 4, 7, 8, 9 } - Requires System.Linq
To use Dictionary
, you need to import System.Collections.Generic
.
using System.Collections.Generic;
Dictionary<string, int> dictionary = new Dictionary<string, int>();
Dictionary<string, int> dictionary = new Dictionary<string, int>()
{
{ "1", 1 },
{ "2", 2 }
};
// Key and Value may be System.ValueTuple
Dictionary<(string, string), (int, int)> dictionary = new Dictionary<(string, string), (int, int)>();
using System.Collections.Generic;
using System.Linq;
Dictionary<string, int> dictionary = new Dictionary<string, int>();
/**** Basic Operations ****/
int size = dictionary.Count(); // Get number of elements of dictionary
string key = "1"; int val = 1;
dictionary.Add(key, val); // Add key and value - if key already in dictionary, throw error
var extractedValue = dictionary[key] // Exctract Value associated with key
bool b = dictionary.ContainsKey(key); // Check if key already in dictionary
/**** Extract Keys and Values ****/
List<string> keys = dictionary.Keys.ToList(); // Get Keys in List - Can also cast to array - Requires System.Linq
int[] values = dictionary.Values.ToArray(); // Get Values in array - Can also cast to List - Requires System.Linq
/**** Comparison Operations ****/
string minKey = dictionary.Keys.Min(); // Get minimum Key
var maxKey = dictionary.Keys.Max(); // Get maximum Key
var minValue = dictionary.Values.Min(); // Get minimum Value
int maxValue = dictionary.Values.Max(); // Get maximum Value
string minKeyByValue = dictionary.MinBy(kvp => kvp.Value).Key; // Get Key with min Value - Requires System.Linq - Work with .Net 6
string maxKeyByValue = dictionary.MaxBy(kvp => kvp.Value).Key; // Get Key with max Value - Requires System.Linq - Work with .Net 6
/**** Loop ****/
foreach(KeyValuePair<string, int> entry in dictionary) {
// do something with entry.Value or entry.Key
}
C# tuples, which are backed by System.ValueTuple types, are different from tuples that are represented by System.Tuple types.
(string, int) t1 = ("test", 3); // System.ValueTuple
Tuple<string, int> t2 = new Tuple<string, int> ("test", 3); // System.Tuple
Here are their main differences:
System.ValueTuple | System.Tuple |
---|---|
value types | reference types |
mutable | immutable |
Data members are fields. | Data members are properties. |
This StackOverflow post says that in general, using System.ValueTuple is preferable to reference-type System.Tuple, because:
(string, int) t1 = ("test", 3);
(double, int) t = (4.5, 3);
var t = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
var t1 = (tupleSum: 4.5, tupleCount: 3);
(double tupleSum, int tupleCount) t2 = (4.5D, 3);
(double tupleSum, int tupleCount) t3 = (Sum: 4.5D, Count: 3);
double tupleSum = 4.5; int tupleCount = 3;
var t4 = (tupleSum, tupleCount);
(string, int) t5 = (tupleSum: 1.2, tupleCount: 6); // Sum and Count will be ignored. It will have the default Item1, Item2
(string, int, int) t1 = ("test", 3, 7);
(double tupleSum, int tupleCount) t2 = (4.5, 3);
/**** Access ****/
var s = t1.Item1; // "test"
int i1 = t1.Item2; // 3
dynamic i2 = t1.Item3; // 7
double d = t2.tupleSum; // 4.5
var i3 = t2.tupleCount; // 3
/**** ToTuple ****/
var t3 = t1.ToTuple();
Tuple<double, int> t4 = t2.ToTuple();
/**** Function returning Tuple ****/
public (int, int, string) FunctionReturnTuple() { return (0, 1, "example"); }
var tuple = FunctionReturnTuple(); // tuple.Item1 = 0 ; tuple.Item2 = 1 ; tuple.Item = "example" ;
// Deconstruct with field names
(int firstInt, int secondInt, string firstString) = FunctionReturnTuple();
var (firstInt, secondInt, firstString) = FunctionReturnTuple();
// Declare with fields names
public (int firstInt, int secondInt, string firstString) FunctionReturnTuple() { return (0, 1, "example"); }
var tuple = FunctionReturnTuple(); // tuple.firstInt = 0 ; tuple.secondInt = 1 ; tuple.firstString = "example" ;
public (int, int, string) FunctionReturnTuple() { return (firstInt: 0, secondInt: 1, firstString: "example"); }
var tuple = FunctionReturnTuple(); // tuple.firstInt = 0 ; tuple.secondInt = 1 ; tuple.firstString = "example" ;
// Declared fields names can be overrided by other field names at deconstruction
public (int firstInt, int secondInt, string firstString) FunctionReturnTuple() { return (0, 1, "example"); }
var (first, second, third) = FunctionReturnTuple(); // OK
var (secondInt, second, third) = FunctionReturnTuple(); // OK - secondInt = 0 - if same field names are used but in another order, order prevail
var t1 = new Tuple<string, int> ("test", 3);
Tuple<string, int> t2 = new Tuple<string, int> ("test", 3);
var t3 = Tuple.Create("test", 3, "7", false);
System.Tuple can’t have custom field names.
Tuple<string, int> t1 = new Tuple<string, int> ("test", 3);
/**** Access ****/
var s = t1.Item1; // "test"
int i1 = t1.Item2; // 3
/**** ToValueTuple ****/
var t2 = t1.ToValueTuple();
(string, int) t3 = t1.ToValueTuple();
(string Name, int tupleCount) t4 = t1.ToValueTuple(); // Can transform in ValueTuple with name fields
To use Queue
, you need to import System.Collections.Generic
.
Queue is a FIFO (or LILO) data structure.
using System.Collection.Generic;
Queue<string> queue = new Queue<string>();
Queue<int> queue = new Queue<int>();
Queue<(int, string)> queue = new Queue<(int, string)>();
Queue<int> queue = new Queue<int>(new[] { 1, 2, 3 }); // Initialization with value
using System.Collection.Generic;
Queue<int> queue = new Queue<int>();
/**** Size ****/
int length = queue.Count; // 0
/**** Insertion: Enqueue ****/
queue.Enqueue(1); // Add to the Queue
queue.Enqueue(2); // Add to the Queue
/**** Comparison Operations ****/
int min = queue.Min(); // 1 - Minimum of Queue
int max = queue.Max(); // 2 - Maximum of Queue
/**** Aggregation Operations ****/
int sum = queue.Sum(); // 3 - Sum of Queue
double average = queue.Average(); // 1.5 - Average of Queue
/**** Access: Dequeue ****/
int i1 = queue.Dequeue(); // 1 - Dequeue oldest element
int i2 = queue.Dequeue(); // 2 - Dequeue oldest element - Dequeue empty Queue throw error
/**** While Loop ****/
while(queue.Count > 0){
// Do something
}
To use Stack
, you need to import System.Collections.Generic
.
Stack is a FILO (or LIFO) data structure.
using System.Collection.Generic;
Stack<string> stack = new Stack<string>();
Stack<int> stack = new Stack<int>();
Stack<(int, string)> stack = new Stack<(int, string)>();
using System.Collection.Generic;
Stack<int> stack = new Stack<int>();
/**** Size ****/
int length = stack.Count; // 0
/**** Insertion: Push ****/
stack.Push(1); // Add to the Stack
stack.Push(2); // Add to the Stack
/**** Comparison Operations ****/
int min = stack.Min(); // 1 - Minimum of Stack
int max = stack.Max(); // 2 - Maximum of Stack
/**** Aggregation Operations ****/
int sum = stack.Sum(); // 3 - Sum of Stack
double average = stack.Average(); // 1.5 - Average of Stack
/**** Access: Pop ****/
int i1 = stack.Pop(); // 1 - Pop newest element
int i2 = stack.Pop(); // 2 - Pop newest element - Pop empty Stack throw error
/**** While Loop ****/
while(stack.Count > 0){
// Do something
}
See: