List<T>
Key points:
- List<T> is the strongly typed collection of objects which needs a parameter such as int, string, object, etc.
- When using List<T> you need to initialize first.
- However List<T> will auto resize as you add or delete elements from List<T> (also called dynamic arrays and vectors).
- One of the benefits is that List<T> prevents database queries from being executed more than once because List<T> loads everything in memory first.
- List<T> fulfills the contract that IEnumerable sets out and allows to store data in the collection.
- You can access the List<T> as enumerable.
- It gets and sets the elements of the collection in arbitrary order and it will only accept lists.
- Accepts null as valid value for reference types and allows duplicates elements
List<T> implements: ICollection
Initializing List<T>
Basic Constructor
var list = new List<int>();
There are various ways to initialize List<T>:
1. Use collection initialize
List<string> list1 = new List<string>() { "crabs", "prawns", "muscles" };
2. Use var keyword with collection initialize
var list2 = new List<string>() { "crabs", "prawns", "muscles" };
3. Use new array as parameter
string[] array = {"crabs","prawns","muscles"}; List<string> list3 = new List<string>(array);
4. Use capacity in constructor and assign (not a good practice)
Listlist4 = new List<string>(3); list4.Add(null); //not good practice list4.Add(null); list4.Add(null); list4[0] = "crabs"; list4[1] = "prawns"; list4[2] = "muscles";
5. Use add method (Preferred way to do)
List<string> list5 = new List<string>(); list5.Add("crabs"); list5.Add("prawns"); list5.Add("muscles");
Object Initialization
Sets the individual fields in the object such as properties. List<T> can hold primitive type, reference and object instances.
using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; namespace Rextester { public class Program { public static void Main(string[] args) { //Initialize list with collection initializer List<Test> list1 = new List<Test>() { new Test(){ A = 1, B = "Monday"}, new Test(){ A = 2, B = "Tuesday"} }; //Initialize list with new objects List<Test> list2 = new List<Test>(); list2.Add(new Test() { A = 3, B = "Sarah"}); list2.Add(new Test() { A = 4, B = "Melanie"}); Console.WriteLine(list1.Count); Console.WriteLine(list2.Count); } class Test { public int A { get; set;} public string B {get; set;} } } }
Accessing List
Properties
Capacity Gets or set total number of elements the collection can hold, it starts with capacity zero and when an element is added then it allocates capacity 4 and it keeps growing exponentially. Sample Code |
Count Gets the total number of elements in the list collection //return the number of items in the list var count = myList.Count; |
Item[Int32] Gets or sets the element at specified index. After adding elements to the list using Add() method, an element is retrieved and displayed using this property. List<int> myList = new List<int>(); //Add method myList.Add(4); myList.Add(5); myList.Add(6); myList.Add(7); myList.Add(8); myList.Add(9); //Item[Int32] property Console.WriteLine("Item at [2]::{0}",myList[2]); |
Iteration
1. Foreach loop if index is not needed
List<int> intList = new List<int>() {10,20,30}; intList.ForEach(el => Console.WriteLine(el)); //with IList IList<int> intList = new List<int>() {10,20,30} foreach( var el in intList) Console.WriteLine(el);
2. For-loop if we want to access indexes
//using for-loop List intList = new List() {10,20,30}; for (var i = 0; i < intList.Count; i++) { Console.WriteLine("Item at {0} value:{1}",i,myList[i]); }
Note:
To loop backwards use Count-1
Implicit Type Cast
With implicit type cast you can enumerate array as List collection
static void PrintData(IList<string> list) { Console.WriteLine("Total: {0}", list.Count); foreach( var val in list) { Console.WriteLine(val); } } static void Main(string[] args) { //array string[] strArray = new string[2]; strArray[0] = "Just"; strArray[0] = "Perfect"; PrintData(strArray); //list List<string> strList = new List<string>(); strList.Add("Another"); strList.Add("Day"); Print(strList); }
Methods
Add() void Add(T item) Adds an object to the end of the collection. It can hold reference types and object instances. Allows duplicates and null reference types, implements ICollection<T>.Add(T) IList<int> myList = new List<int>(); //Add method myList.Add(4); myList.Add(5); myList.Add(6); myList.Add(7); myList.Add(8); myList.Add(9); //Adding String IList<string> strList = new List<string>(); strList.Add("one"); strList.Add("two"); strList.Add("three"); strList.Add(null); //Adding object to list IList<Pupil> pupilList = new List<Pupil>(); pupilList.Add(new Pupil()); pupilList.Add(new Pupil()); //Adding objects during initialization IList<int> intList = new List<int>(){10,20,30,40}; IList<Pupil> pupliList = new List<Pupil>() { new Pupil(){pupilID=1, Name="Sam"}, new Pupil(){pupilID=2, Name="Sarah"}, new Pupil(){pupilID=3, Name="Jane"}, }; |
AddRange void AddRange(IEnumerable Adds the entire collection of elements into the list at the end of the first collection, can pass any IEnumerable collection such as array but both collection need to be same datatype Note: AddRange will only work with List, IList doesn't include AddRange() method Parameter Type: System.Collections.Generic.IEnumerable List |
BinarySearch() Returns zero-based index of the item in the sorted list. Negative number is returned if no item is found. Only works if the type T implements IComparable<T> List |
Clear Erases the entire List collection, count becomes zero and capacity is unchanged IList<int> intList = new List<int>() {1,2,3,4}; intList.Clear(); |
Contains Scans the list to find an specific element, takes one parameter whereas LINQ method takes 2 argument, it has Boolean return IList<int> intList = new List<int>() {1,2,3,4}; intList.Contains(6); -- returns false |
ConvertAll() Converts all the elements in the current List<T> to another generic type and returns the converted collection. using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; namespace Rextester { public class Program { public static void Main(string[] args) { List |
CopyTo() public void CopyTo (T[] array) Copies the list collection to a compatible one-dimensional array, the type of the array must be equivalent to List<T>. The array must have zero based indexing Overloads: list.CopyTo(array) 2. Copies all list items into the array, from a specified array index list.CopyTo(array, arrayIndex: num) 3. Copies a range of list items into the array, starting from the specified array index list.CopyTo(index:num, array:array, arrayIndex:num, count:1) Exceptions: using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; namespace Rextester { public class Program { public static void Main(string[] args) { var myList = new List<int>() {12,13,15}; int[] arrayList = new int[15]; //copy entire list to the end of array myList.CopyTo(arrayList); //copy list starting at index 3 myList.CopyTo(arrayList,3); //param: index, array, arrayindex, count myList.CopyTo(2,arrayList,8,1); for (var i = 0; i < arrayList.Count(); i++) { Console.WriteLine("Array Index {0} - Value : {1}",i,arrayList[i]); } } } } |
Exists bool Exists (Predicate Use to search an element in List<T> collection. Returns true if the list contains the specified matching predicate or returns false if it doesn't match the predicate. You can use lambda expression for your predicate. The alternative to exists is for loop with the if condition or Any() LINQ method. List<int> list = new List<int>(); list.Add(7); list.Add(11); list.Add(13); // See if any elements with values greater than 10 exist. bool exists = list.Exists(element => element > 10); Console.WriteLine(exists); // Check for numbers less than 7. exists = list.Exists(element => element < 7); Console.WriteLine(exists); |
Equals() public virtual bool Equals (object obj) Returns true if the two lists are equal with the same instance. To determine if all items of the 2 two are equal use SequenceEqual LINQ method. var listA = new List<int>() {1,2,3}; var listB = listA; bool result = listA.Equals(listB); -- result: true var listA = new List<int>() { 9, 6, 2 }; var listB = new List<int>() { 9, 6, 2 }; bool result = listA.Equals(listB); -- result: false |
Find() public T Find (Predicate Returns the first match from the predicate, if no item matches then it will return zero. Starts searching from the beginning and stops as it finds the first match. If just checking the matching value then Exists will do the job. List<int> list = new List<int>(new int[] { 39, 27, 47 }); int result = list.Find(item => item > 20); |
FindAll() FindAll(Predicate Returns the list of elements matching the specified predicate in the List<T>. It returns empty if there is no matched result. var listB = listA.FindAll(x => x > 2); |
FindIndex() Returns zero-based index of the first item which matches the soecified predicate. Returns -1 if no matching results found. int index = list.FindIndex( x => x < 10); Overloads: int index = list.FindIndex(startIndex:num, match: x => x < 6); Returns index of the first item which matches the predicate and specified start and end index range of the list int index = list.FindIndex(startIndex:num,count:num, match: x => x < 6); |
FindLast() Returns the last predicate matching item from the list. For collection it returns the empty collection of generic if no predicate matching result found. int item = list.FindLast(x => x < 5); |
FindLastIndex() Returns zero-based index of the last predicate matched item. int index = list.FindLastIndex(x => x < 5); Overloads: int index = list.FindLastIndex(startIndex: 2, match: x => x < 5); Returns index of the last item which matches the predicate and specified start and end index range of the list int index = list.FindLastIndex(startIndex:num,count:num, match: x => x < 6); |
ForEach Same function as foreach statement in C#, executes each item in the list list.ForEach( x => { Console.WriteLine(x);}) |
GetEnumerator Returns an enumerator that iterates through the List<T>. It is just used to read the data in the collection, however due to the complexity foreach loop is preferred over getenumerator() method. It is possible to write methods that acts on IEnumerator interface. Note: IEnumerator is not same as IEnumerable. public class Program { public static void Main(string[] args) { List<int> list = new List<int>(new int[] { 39, 27, 47 }); List<int>.Enumerator e = list.GetEnumerator(); Write(e); } public static void Write(IEnumerator |
GetHashCode() Is a default hash function, returns hash code for current object. A hash code is a numeric value that is used to insert and identify an object in a hash-based collection such as Dictonary. The GetHashCode() method provides the algorithm for object equality. Note: 1. It is not recommended to serialize or store hash code in database. 2. When you override GetHashCode() method, you should also override Equals() method and vice versa. |
GetRange Returns a list with the range of items from the list collection. This is similar to Take and Skip in LINQ var listB = listA.GetRange(index:1, count: 3); |
IndexOf Determines the element index of a certain value in the List collection. Searches by value and returns the location. Returns -1 if the value not found. int index = list.IndexOf(8); Overloads: int index = list.IndexOf(item: 8, index: 1); 2. Returns the index of the first occurrence of the item in the list. It searches the list in the range specified by index and count. int index = list.IndexOf(item: 3, index: 1, count: 2); |
Insert void Insert(int index, T item) Inserts an element into the List<T> at the specified index. It is slow method, consider using Queue or LinkedList for better performance. list.Insert(index: 1, item: 5); ---- IList<int> intList = new List<int>() {1,2,3,4}; intList.Insert(2,20) -- insert 20 at index 2; |
InsertRange Adds the entire collection of elements to the specified index of a list, it handles collections that implement IEnumerable. The List resizes to accomodate the inserted objects. List<int> myList = new List<int>() {1,2,3,4,5}; int[] myArray = new int[3] {7,9,6}; myList.InsertRange(1, myArray); myList.ForEach( x => { Console.WriteLine(x);}); |
Remove() bool Remove(T item) Remove an element from the list collection by value IList<int> intList = new List<int>() {100, 200, 300, 400, 500}; intList.Remove(200); -- removes 200 from the list |
RemoveAt() void RemoveAt(int index) Removes an element from list collection at specified index IList<int> intList = new List<int>() {100, 200, 300, 400, 500}; intList.RemoveAT(1); -- removes 200 from the list (index starts at zero so value for index 1 is 200) |
RemoveRange() Removes elements from the specified range List<int> myList = new List<int>() {8,3,6,3}; -- myList.RemoveRange(index: 2, count: 3) myList.RemoveRange(2,3); |
Reverse() Reverses the order of all elements in the list collection List<int> myList = new List<int>() {8,3,6,3}; myList.Reverse(); ---result: 3,6,3,8 Overload: List<int> myList = new List<int>() {8,3,6,3}; --- myList.Reverse(index: 1, count: 2) myList.Reverse(1, 3); --- result 8,6,3,3 |
Sort() Orders the elements in the List This List List<int> myList = new List<int>() {8,3,6,3}; myList.Sort(); --- result 3,3,6,8 Overloads: List<int> myList = new List<int>() {8,3,6,3}; myList.Sort(x,y) => x.CompareTo(y)); --- result 3,3,6,8 Sort list using comparison delegate in descending order List<int> myList = new List<int>() {8,3,6,3}; myList.Sort(x,y) => y.CompareTo(x)); --- result 8,6,3,3 Sort using custom comparer List<int> myList = new List<int>() {8,3,6,3}; myList.Sort(new myComparer()); --- result 3,3,6,8 Sort the specified range using the custom comparer List<int> myList = new List<int>() {8,3,6,3}; --- myList.Sort(index:2, count:2, comparer: new MyComparer()) myList.Sort(2,2,new myComparer()); myList.ForEach( x => { Console.WriteLine(x);}); --- result 8,3,3,6 public class MyComparer : IComparer |
ToArray() Creates new array and copies all elements into it. If the list is empty then it returns an empty array. List<int> myList = new List<int>() {8,3,6,3}; int[] array = list.ToArray(); |
TrimExcess() Trims the list capacity to reduce memory usage if it's reasonable. It sets Capacity to the same value as Count but only if the Count is less than about 90 % of Capacity. If the count is almost the same as the list capacity it does nothing. List<int> myList = new List<int>() {1,2,3,4,5}; -- list.count = 5 -- list.capacity = 8 list.TrimExcess(); -- list.count = 5 -- list.capacity = 5 |
TrueForAll() bool TrueForAll(Predicate It returns true if the specified condition is evaluated true otherwise is false. The predicates can be defined as a lambda expression or predicate type delegate. IList<int> intList = new List<int>() {100, 200, 300, 400, 500}; bool result = intList.TrueForAll( s => s % 2 == 0) --Predicate type delegate static bool isPositiveInt(int i) { return i > 0; } static void Main(string[] args) { List<int> intList = new List<int>(){10, 20, 30, 40}; bool res = intList.TrueForAll(isPositiveInt); } |
Using String functions with List<T>
string.Join
We can use string.join method to join strings in the List collection. With the help of ToArray() instance method you can generate a comma-delimiter string for older version.
List<string> myList = new List<string>() { "New York", "California", "Nevada", "Arizona" }; -- older version string strCity = string.Join(" , ", myList.ToArray()); -- new version string strCity = string.Join(" , ", myList); Console.WriteLine(strCity);
Other functions: TrimEnd, TrimStart
StringBuilder
With string builder you can convert a List of any object to string such as Append() method.
List for Dictionary Keys
List constructor can be used to retrieve the list of keys from a Dictionary. One of the best ways to iterate over Dictionary keys. Note: the key property the enumerable collection of keys but List is better.
public class Program { public static void Main(string[] args) { var myDictionary = new Dictionary(); myDictionary.Add(2,true); myDictionary.Add(4,true); myDictionary.Add(6,false); myDictionary.Add(8,false); List<int> keys = new List<int>(myDictionary.Keys); foreach(int key in keys) Console.WriteLine(key); } }
Performance
1. Adding and Removing in the middle: O(n)
2. Adding and Removing in the end: O(1)
3. Searching: IndexOf, Contains, Find : O(n)
4. Searching with Index: O(1)
When to use?
1. Better to use List<> than array even working with fixed set of items
2. List is best for adding or removing items at the end of a list
3. List is best to access items by index which is fast and efficient
4. It is better to use Dictionary for search than list
IEnumerables to List
IEnumerablee = source.Select(c = > c.ToString()); List l = source.Select(c = > c.ToString()).ToList();