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, IEnumerable, IList,IReadOnlyCollection, IReadOnlyList, IList

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)

            List list4 = 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");

Source Code

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 collection)
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 numberListA = new List<int>();
            numberListA.Add(2);
            numberListA.Add(4);
            numberListA.Add(6);
            
            List numberListB = new List<int>();
            numberListB.Add(25);
            numberListB.Add(45);
            numberListB.Add(65);
            //Add Range
            numberListA.AddRange(numberListB);
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 myList = new List() {1,2,3,4,5,6};
int index = myList.BinarySearch(6);
Console.WriteLine("Print Result {0}", index);
--overloads comparer
public class MyComparer : IComparer
{
    public int Compare(int x, int y) { return x.CompareTo(y); }
}
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 student = new List
                {
                    new Student {Name="jacinta", Age="40"},
                    new Student {Name="Robby", Age="46"}    
                };
                //Convert student to CompStudent
                List compStudent = student.ConvertAll(x => new CompStudent
                   {
                         CName = x.Name, CAge = x.Age
                    });
            
                //Alternative method
                List cStudent = new List();
                foreach(Student s in student)
                {
                    cStudent.Add(new CompStudent {CName = s.Name, CAge = s.Age});
                }
        }
        
        public class Student
        {
            public string Name { get; set;}
            public int Age {get; set;}
        }
        
        public class CompStudent
        {
            public string CName { get; set;}
            public int CAge { get; set;}
        }
        
    }
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:
1. Copies all list items to the beginning of the specified array

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:
1. ArgumentNullException - if the array is null
2. ArgumentException - if the source generic list element is greater than the destination array length

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 match);
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 match);
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:
Returns index of the first item which matches the predicate and specified start index of the list

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:
Returns the index of the last item matching the predicate from the specified index as the beginning of the search list.

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 e)
        {
            while (e.MoveNext())
            {
                int val = e.Current;
                Console.WriteLine(val);
            }
        }
    }
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:
1. Returns the index of the first occurrence of the item in the list. It searches the list from the specified index to the end of the list.

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:
Reverses the order of the elements in the specified range

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 method works only if the type T implements IComparable or IComparable interface.

List<int> myList = new List<int>() {8,3,6,3};
myList.Sort();
--- result 3,3,6,8

Overloads:
Using comparison delegate

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
{
    public int Compare(int x, int y) { return x.CompareTo(y); }
}
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 match)
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

IEnumerable e = source.Select(c = > c.ToString());
List l = source.Select(c = > c.ToString()).ToList();

Leave a Reply

Your email address will not be published. Required fields are marked *