Как написать list c

List<T> — класс из пространства имен System.Collections.Generic, список однотипных объектов. В отличие от массива, предоставляет набор методов, облегчающих работу, таких как добавление новых элементов (это удобно, когда неизвестно заранее сколько будет элементов).

Есть несколько вариантов создания списка:

Создание списка без начальных значений

        //List<T> list = new List<T>(); //T - выбранный тип, например int
//Пример:
List<int> list = new List<int>();
//Примеры других типов:
List<string> sList = new List<string>();
List<object> oList = new List<object>();


    

Нет ограничений на тип, который можно поместить в список.

Создание списка с начальными значениями

        //List<T> list = new List<T>(){ Item1, Item2, Item3… }; //Item1/2/3 - элементы нашего списка, тип которых T
//List<T> list = new List<T>{ Item1, Item2, Item3… }; // Тоже допустимо
//Пример:
List<int> list = new List<int> { 1, 2, 3 }; //Мы создали список с набором чисел

    

Создание на основе другого списка

        List<int> list = new List<int> { 1, 2, 3 };
List<int> list2 = new List<int>(list); 

    

Надо заметить, что это не то же самое, что и list2 = list, т. к. при передаче списка в конструктор нового списка создается именно новый список, т. е. в памяти выделяется место для нового объекта, но заполняется теми же значениями, которые были в переданном списке.

Комбинированный подход

        List<int> list = new List<int> { 1, 2, 3 };
List<int> list2 = new List<int>(list) { 4 };

    

Если вывести все значения из списка list2, будут выведены значения от 1 до 4.

Также рассмотрим более сложный пример с пользовательским классом.

        class Cup
{
    public string Name { get; set; }
    public int Capacity { get; set; }
    public ConsoleColor Color { get; set; }
    public Cup(string name)
    {
        Name = name;
    }
}
List<Cup> cups = new List<Cup>
{
		new Cup("Моя кружка") {
				Color = ConsoleColor.White,
				Capacity = 1000
		},
		new Cup("Не моя кружка") {
				Color = ConsoleColor.Black,
				Capacity = 300
		}
};

    

Установка начальной емкости списка

Помимо перечисленных выше конструкторов, есть еще один, который принимает размер начальной емкости списка:

        List<int> list = new List<int>(10);

    

Внутри списка находится массив, который при заполнении определенной емкости динамически расширяется, чтобы снизить издержки на выделение памяти при добавлении элементов. На низком уровне при проверке расширения проверяется, если в массиве (который внутри списка) нет элементов, то его размер выставляется равным _defaultCapacity (переменная в исходниках, которая имеет начальное значение = 4), в противном случае считается из «количество элементов» * 2. Т. е. всякий раз, когда мы достигаем определенной границы массива, List автоматически расширяет его в 2 раза, однако ограничение списка — это 2G (Array.MaxArrayLength – 2146435071) элементов. Для повышения производительности, если известен конечный размер списка, можно изначально задать его размер, что избавит от дополнительных выделений памяти.

Обращение к элементам списка

Аналогично как в массиве, допустимо обращаться к элементам списка в квадратных скобках по индексу.

        List<int> list = new List<int>() { 3, 4, 2, 0 };
Console.WriteLine(list[0]);// 3
list[0] = 7;
Console.WriteLine(list[0]);// 7
List<int> list1 = new List<int>();
list1[0] = 1; // Получим исключение ArgumentOutOfRangeException, т.е. для начала нужно создать хоть один элемент списка

    

Доступ к элементам списка

Доступ к элементам списка

Длина списка

Для определения длины списка используется свойство Count.

        List<int> list = new List<int>() { 3, 4, 2, 0 };
Console.WriteLine(list.Count); // 4
list = new List<int>();
Console.WriteLine(list.Count); // 0

    

Получение длины списка

Получение длины списка

Перебор списка

Для перебора списка можно использовать классический цикл, например for.

        List<int> list = new List<int>() { 3, 4, 2, 0 };
for(int i = 0; i < list.Count; i++)
		Console.WriteLine(list[i]);

    

Перебор списка for

Перебор списка for

Также существует специальный цикл для работы со списками foreach.

        List<int> list = new List<int>() { 3, 4, 2, 0 };
foreach(int item in list)
		Console.WriteLine(item);

    

Перебор списка foreach

Перебор списка foreach

Методы списка

Наконец, добрались до самого интересного — методы, которые улучшают работу со списком по сравнении с массивом. Рассмотрим следующие методы (полный список методов можно посмотреть в документации Microsoft):

Добавление в список

  • void Add(T item) — добавляет новый элемент с типом T в конец списка.
  • void AddRange(IEnumerable<T> collection) — добавляет в список коллекцию или массив в конец списка.
  • void Insert(int index, T item) — вставляет элемент в коллекцию по указанному индексу. При выходе за границы коллекции (0 > index или Count-1 < index) будет сформировано исключение System.ArgumentOutOfRangeException.
  • void InsertRange(int index, IEnumerable<T> collection) — аналогично методу выше, только вставляет список элементов по указанному индексу. Также при выходе за границы будет сформировано исключение System.ArgumentOutOfRangeException.

Поиск и проверка элемента

  • int BinarySearch(T item) — бинарный поиск элемента в списке, возвращает индекс элемента. Работает корректно, если список отсортирован. Имеет еще два варианта реализации с дополнительными параметрами для корректного сравнения элементов или указания начальной точки поиска.
  • bool Contains(T item) — проверка наличия элемента в списке.
  • bool Exists(Predicate<T> match) — проверяет наличие в списке хотя бы одного элемента удовлетворяющего условиям делегата match.
  • T Find(Predicate<T> match) — возвращает первый элемент, удовлетворяющий условиям делегата match.
  • List<T> FindAll(Predicate<T> match) — аналогичен Find, только возвращает все элементы.
  • int FindIndex(Predicate<T> match) — возвращает первый индекс элемента, удовлетворяющего условиям делегата match. Имеет еще два варианта реализации с указанием позиции поиска и количества элементов.
  • int FindLastIndex(Predicate<T> match) — аналогично FindIndex, только возвращает индекс последнего элемента, удовлетворяющего условиям делегата match. Также имеет еще два варианта реализации с указанием позиции поиска и количества элементов.
  • List<T> GetRange(int index, int count) — этот метод получает подсписок из списка от указанного индекса с указанным количеством элементов.
  • int IndexOf(T item) — возвращает первый индекс элемента, если он найден в списке либо -1. Также имеет еще два реализации с указанием позиции поиска и количества элементов.
  • int LastIndexOf(T item) — возвращает последний индекс элемента, если он найден в списке либо -1. Также имеет еще два реализации с указанием позиции поиска и количества элементов.

Удаление из списка

  • bool Remove(T item) — удаляет первое вхождение указанного элемента из списка. Возвращает true, если элемент был удален или false, если нет.
  • int RemoveAll(Predicate<T> match) — удаляет все элементы, удовлетворяющие условиям делегата match. Возвращает количество удаленных элементов.
  • void RemoveAt(int index) — удаляет элемент списка с указанным индексом. При выходе индекса за границы списка формирует исключение System.ArgumentOutOfRangeException.
  • void RemoveRange(int index, int count) — удаляет элементы массива с указанного индекса в указанном количестве. Если index меньше 0 или значение параметра count меньше 0, то будет сформировано исключение System.ArgumentOutOfRangeException. Если параметры index и count не указывают допустимый диапазон элементов в списке, будет сформировано исключение System.ArgumentException.
  • void Clear() — удаляет все элементы из списка.

Сортировка списка

  • void Sort() — сортирует элементы. В основе лежит алгоритм быстрой сортировки с ограничением глубины рекурсии до 32, при достижении которого используется сортировка кучей.
  • void Reverse() — изменяет порядок элементов во всем списке на обратный. Имеет перегруженную версию, в которой указывается начальный индекс и количество элементов.

Прочее

  • List<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter) — позволяет сконвертировать все типы элементов текущего списка в другой тип. На входе принимает делегат на метод, преобразующий объект от одного типа к другому.
  • void CopyTo(T[] array) — копирует список в массив. Имеет еще 2 варианта реализации с указанием границ и позиций копирования.
  • void ForEach(Action<T> action) — это аналог цикла foreach, только в качестве итерации будет выполняться метод, который на входе принимает элемент с типом T. Еще одно отличие такого цикла от foreach состоит в том, что в методе не сработает ни break, ни continue. Аналогом continue при таком подходе можно считать return.
  • T[] ToArray() — возвращает массив элементов списка.

Примеры

Добавление в список

В этом примере мы создадим массив и разными способами заполним его в цикле.

        List<int> list = new List<int>();
for (int i = 0; i < 10; i++)
{
    list.Add(i); // Добавление элемента в конец списка
    list.AddRange(new[] { i + 4, i + 5 }); // Добавление коллекции элементов в конец списка
    list.Insert(i, i + 1); // Вставка элемента по индексу i
    list.InsertRange(i, new[] { i + 2, i + 3 }); // Вставка массива/коллекции по индексу i
}

    

Удаление из списка

        List<int> list = new List<int>() { 0, 1, 2, 9, 32, -7 }; // Создали массив с элементами
Console.WriteLine(string.Join(",", list));
if (list.Remove(9)) // Удаляем 9
    Console.WriteLine("Элемент 9 успешно удален.");
Console.WriteLine(string.Join(",", list));
list.RemoveAt(0); // Удаляем 0
Console.WriteLine(string.Join(",", list));
list.RemoveAll(i => i < 0); // Удаляем -7
Console.WriteLine(string.Join(",", list));
list.RemoveRange(0, 2); // Удаляес 1 и 2
Console.WriteLine(string.Join(",", list));
list.Clear(); // Удаляем все оставшиеся элементы - 32
Console.WriteLine(string.Join(",", list));

    

Удаление данных из списка

Удаление данных из списка

Поиск и проверка элемента

        List<int> list = new List<int> { 0, 0, 1, -7, 9, 2, 32, 16, 42 };

//Индексы
//Поиск первого четного индекса
Console.WriteLine(list.FindIndex(i => i % 2 == 0)); // 0

//Поиск последнего четного индекса
Console.WriteLine(list.FindLastIndex(i => i % 2 == 0)); // 8

//Поиск индекса по числу из списка
Console.WriteLine(list.IndexOf(-7)); // 3

//Попробуем найти индекс числа которого нет в списке
Console.WriteLine(list.IndexOf(13)); // -1

//Поиск последнего индекса по числу из списка
Console.WriteLine(list.LastIndexOf(0)); // 1

list.Sort(); // Отсортируем массив, так как это основное условие бинарного поиска
Console.WriteLine(list.BinarySearch(9)); // 5

//Проверка вхождения
//Проверим есть ли в списке четные числа
Console.WriteLine(list.Exists(i => i % 2 == 0)); // true

Console.WriteLine(list.Contains(0)); // true
Console.WriteLine(list.Contains(13)); // false

//Значения
//А теперь получим первое четное число
Console.WriteLine(list.Find(i => i % 2 == 0)); // 0

//Найдем все четные числа
Console.WriteLine(string.Join(",", list.FindAll(i => i % 2 == 0))); // 0,0,2,16,32,42

//Последнее четное число
Console.WriteLine(string.Join(",", list.FindLast(i => i % 2 == 0))); // 42

//Получим подсписок, первые 4 элемента
Console.WriteLine(string.Join(",", list.GetRange(0, 4))); // -7,0,0,1

    

Получение диапазона и копирование в массив

        List<int> list = new List<int> { 0, 0, 1, -7, 9, 2, 32, 16, 42 }; 

var range = list.GetRange(2, 3); // Получим диапазон/подсписок
int[] part = new int[range.Count]; // Объявим массив куда будем копировать диапазон
range.CopyTo(part); // Скопируем диапазон

Console.WriteLine(string.Join(",", part)); // 1,-7,9

    

Работа с диапазоном

Работа с диапазоном

Расположение элементов в обратном порядке

        List<int> list = new List<int> { 0, 0, 1, -7, 9, 2, 32, 16, 42 };

list.Reverse();
Console.WriteLine(string.Join(",", list)); // 42,16,32,2,9,-7,1,0,0

list.Reverse(1, 3);
Console.WriteLine(string.Join(",", list)); // 42,2,32,16,9,-7,1,0,0

    

Построение элементов в обратном порядке

Построение элементов в обратном порядке

***

В статье рассмотрена работа с коллекцией List, рассмотрена базовая работа (инициализация, обращение к данными) и методы для работы со списком:

  1. Добавление.
  2. Поиск.
  3. Удаление.
  4. Сортировка.
  5. Работа с диапазонами.

Материалы по теме

  • 👨‍🎓️ Самоучитель по C#: абстрактные классы и члены классов
  • 👨‍🎓️ Учебник по C#: работа с коллекциями Dictionary
  • 🧊 Руководство по С# для начинающих: массивы и цикл foreach

Время на прочтение
7 мин

Количество просмотров 18K

List является одной из самых популярных коллекций в C#. Давайте разберёмся в некоторых особенностях работы с ним и посмотрим на внутреннюю реализацию его отдельных частей.

Введение

Данная статья будет посвящена полностью List<T> из пространства имён System.Collections.Generic, а если быть конкретнее, то его внутренней реализации и некоторым особенностям. Это самая часто используемая коллекция языка. И это не только моё мнение — так писали в своих книгах Эндрю Троелсен, Филипп Джепикс и Джон Скит. И это понятно – с List<T> легко работать. Он довольно гибкий и тем самым покрывает огромную часть повседневных задач программиста. С этим также помогает большое количество методов, идущих с ним в комплекте. А наличие LINQ ещё больше расширяет возможности данной коллекции.

Внутри List

Исходный код класса List<T> доступен на GitHub. Это значит, что мы можем взглянуть на его реализацию. Пройдёмся по важным аспектам.

Класс List<T> представляет последовательный список элементов с динамически изменяемым размером. Под капотом List<T> построен с использованием массива.

Класс List<T> содержит 3 основных поля:

  • T[] _items – внутренний массив, на основе которого строится список;

  • int _size – хранит информацию о количестве элементов в списке;

  • int _version – содержит версию коллекции.

Добавление элемента в список

Как уже было сказано, размер списка динамически изменяется. Взглянем поподробнее, что же происходит при добавлении элемента в список.

public void Add(T item)
{
  _version++;
  T[] array = _items;
  int size = _size;
  if ((uint)size < (uint)array.Length)
  {
    _size = size + 1;
    array[size] = item;
  }
  else
  {
    AddWithResize(item);
  }
}

В первую очередь значение поля _version увеличивается на 1 (смысл данного действия мы разберём чуть позже). После этого происходит создание двух локальных переменных – массива array с элементами типа T и size типа int. Им присваиваются соответствующие поля. Далее если в массиве ещё есть место для одного элемента, то происходит изменение элемента массива по индексу size + 1. Если же размер массива не позволяет добавить ещё один элемент, то вызывается метод AddWithResize.

private void AddWithResize(T item)
{
  Debug.Assert(_size == _items.Length);
  int size = _size;
  Grow(size + 1);
  _size = size + 1;
  _items[size] = item;
}

Здесь вызывается метод Grow для увеличения текущего размера внутреннего массива. Далее производятся те же действия, что и в методе Add, для добавления при доступном месте.

Рассмотрим метод Grow подробнее:

private void Grow(int capacity)
{
  ....

  int newcapacity = _items.Length == 0 ? DefaultCapacity : 2 * _items.Length;

  if ((uint)newcapacity > Array.MaxLength) newcapacity = Array.MaxLength;

  if (newcapacity < capacity) newcapacity = capacity;

  Capacity = newcapacity;
}

Алгоритм работы метода Grow:

  • если внутренний массив пуст, то ёмкость списка будет равна 4, иначе удвоенной длине массива;

  • если новое значение ёмкости получается больше максимально возможной длины массива, то данная ёмкость станет равна Array.MaxLength;

  • если новое значение ёмкости коллекции получилось меньше текущего, то новая ёмкость станет равна текущей;

  • в конце newcapacity записывается в свойство Capacity.

Зачем нужно поле _version?

Но зачем же всё-таки нужно поле _version, значение которого менялось в методе Add? Как уже было написано ранее, это поле, которое позволяет отслеживать версию списка. Его значение проверяется при обходе списка. К примеру, рассмотрим метод ForEach:

public void ForEach(Action<T> action)
{
  ....
  int version = _version;

  for (int i = 0; i < _size; i++)
  {
    if (version != _version)
    {
      break;
    }
    action(_items[i]);
  }

  if (version != _version)
    ThrowHelper
      .ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion();
}

Перед началом обхода значение поля _version сохраняется в переменную. Если во время обхода список будет изменён, то обход прекращается и выбрасывается исключение типа System.InvalidOperationException. Похожим образом _version отслеживается и в List<T>.Enumerator. Поэтому изменение списка при его обходе в foreach также приведёт к выбрасыванию исключения.

Capacity

У List<T> есть конструктор, который первым аргументом принимает число – начальную ёмкость.

List<int> list = new List<int>(8);

Если разработчик заранее знает нужный размер списка, то он может задать его. Это избавляет от ненужных операций копирования и выделения памяти под новый массив при добавлении новых элементов.

Кстати, размером внутреннего массива можно управлять, ещё и используя свойство Capacity:

list.Capacity = 8;

Рассмотрим код данного свойства:

public int Capacity
{
  get => _items.Length;
  set
  {
    if (value < _size)
    {
      ThrowHelper.ThrowArgumentOutOfRangeException(....);
    }

    if (value != _items.Length)
    {
      if (value > 0)
      {
        T[] newItems = new T[value];
        if (_size > 0)
        {
          Array.Copy(_items, newItems, _size);
        }
        _items = newItems;
      }
      else
      {
        _items = s_emptyArray;
      }
    }
  }
}

Аксессор get возвращает значение _items.Length, то есть длину внутреннего массива.

Аксессор set действует по следующему алгоритму:

  • если value меньше количества элементов в коллекции, то будет выброшено исключение;

  • если value не равно длине внутреннего массива и value больше 0, то будет создан новый массив с ёмкостью, равной value;

  • если количество элементов в списке больше 0, то будет выполнено копирование элементов из старого массива в новый;

  • если value равно 0, то полю, которое представляет собой внутренний массив, будет присвоен пустой массив.

Прочие особенности методов List

Insert

Метод Insert позволяет вставить элемент в коллекцию только в рамках начала и конца этой коллекции. Если количество элементов в коллекции будет равно размерности внутреннего массива, то произойдёт увеличение ёмкости массива с помощью метода Grow(_size + 1). При попытке вставить элемент на индекс, который больше list.Count, будет выброшено исключение System.ArgumentOutOfRangeException.

List<string> list = new List<string>() { "1", "2"};
list.Insert(1, "10"); // OK
list.Insert(2, "15"); // OK
list.Insert(10, 12);  // throw exception

Подобное поведение останется даже при явном управлении размером внутреннего массива.

Рассмотрим пример:

List<string> list = new List<string>() { "1", "2"};
list.Capacity = 8;
list.Insert(3, "3");

В свойство Capacity присваивается 8, что приводит к изменению размера внутреннего массива. Однако это не даёт возможности вставить элемент на позицию, превышающую list.Count. Результатом выполнения приведённого кода будет выбрасывание исключения.

Clear

Данный метод производит очистку коллекции. В результате этой операции свойство Count будет иметь значение 0. Элементы коллекции ссылочного типа получают значение по умолчанию. Если элементы коллекции являются структурами и имеют поля ссылочного типа, то данные поля тоже получат значение по умолчанию. Стоит заметить, что размер внутреннего массива остаётся неизменным. Если до вызова Clear свойство Capacity было равно 8, то и после Clear размер массива останется равным 8. Для освобождения памяти, выделяемой под сам массив, необходимо после Clear вызвать метод TrimExcess.

TrimExcess

Данный метод делает размер внутреннего массива равным количеству элементов в списке. Его стоит использовать, например, когда вы знаете, что в коллекцию больше не будут добавлены новые элементы.

list.Clear();
list.TrimExcess();

Sort и OrderBy

Между двумя этими методами есть несколько различий:

  • метод Sort принадлежит классу List<T>, а метод OrderBy является методом расширения из LINQ;

  • метод Sort модифицирует исходную коллекцию, а OrderBy возвращает отсортированную копию с типом IOrderedEnumerable<TSource>;

  • метод OrderBy производит устойчивую сортировку, а Sort – нет. Если вы используете метод Sort, то эквивалентные элементы могут быть переупорядочены.

Немного о производительности

List против ArrayList

List<T> является обобщённым, а это значит, что мы должны при создании списка указать, с объектами какого типа он работает.

List<string> list = new List<string>();

Джеффри Рихтер в своей книге «CLR via C#» приводит следующие преимущества обобщений:

  • защита исходного кода;

  • безопасность типов;

  • более простой и понятный код;

  • повышение производительности.

В той же книге в начале 12-ой главы про обобщения имеется хороший пример сравнения List<T> и его необобщённого аналога ArrayList. Суть теста заключается в добавлении элемента в список и присваивании этого же элемента из списка в переменную 10 миллионов раз.

Пример кода для тестирования ArrayList со значимым типом:

public void ValueTypeArrayList()
{
  ArrayList a = new ArrayList();
  for (Int32 n = 0; n < _count; n++)
  {
    a.Add(n);
    Int32 x = (Int32)a[n];
  }
}

Тестирование производилось с объектами значимых (Int32) и ссылочных (String) типов.

Переписав приведённый в книге код и протестировав его с помощью BenchmarkDotNet, я получил следующие результаты:

Из результатов видно, что c Int32 алгоритм List<T> работает гораздо быстрее, чем ArrayList. В целых 13 раз! Плюс с List<T> в 4 раза меньше выделяется память.

Из-за того что при работе ArrayList производится множество операций упаковки, увеличивается и число сборок мусора. При этом получение элемента требует выполнения распаковки. Всё это приводит к снижению производительности.

Разница при использовании ссылочных типов несущественная, так как нет операций упаковки и распаковки, которые являются очень тяжёлыми. Судя по коду, небольшая разница в скорости появляется из-за операции преобразования типов.

Преимущества задания Capacity

Как уже было сказано ранее, если разработчик заранее знает размер списка, то он может указать его.

Проведём небольшой тест.

public void ListWithoutCapacity()
{
  for (int i = 0; i < Count; i++)
  {
    List<int> list = new List<int>();
    for (int j = 0; j < Length; j++)
    {
      list.Add(j);
    }
  }
}

В данном случае происходит добавление в list 150 000 элементов. Для наглядности проведём эту операцию 1000 раз. И сравним производительность с таким же методом, но с указанным capacity, который равен количеству операций добавления.

Из результатов видно, что затраченное время на выполнение метода без capacity в 2 раза больше, чем с заранее установленным. Также памяти выделяется почти в 4 раза больше. Подобные действия убирают 17 ненужных операций копирования на каждой итерации внешнего цикла.

Как быстрее всего определить, что в списке есть элементы?

Возьмём три варианта определения того, что список непустой:

  • использовать метод Count из LINQ и сравнить результат с 0;

  • использовать свойство Count и сравнить результат с 0;

  • использовать метод расширения Any из LINQ.

Проведя тестирование, получаем следующие результаты для списка из 1 500 000 элементов:

Самым быстрым оказался доступ к свойству Count, так как оно просто возвращает значение поля _size.

Метод Count пытается преобразовать исходную коллекцию к ICollection. При успешном преобразовании метод вернёт значение свойства Count. В случае неудачи потребуется обойти всю коллекцию для высчитывания количества элементов. К счастью, List<T> реализует данный интерфейс.

Метод Any при обнаружении хотя бы одного элемента в коллекции вернёт true.

Заключение

Можно сказать, что List<T> является более удобной для работы версией массива. Например, со списком удобнее работать, когда заранее неизвестно количество элементов последовательности.

C# содержит ещё множество коллекций, которые помогают в работе разработчикам. Какие-то из них более специфичные, а какие-то менее. Надеюсь, что данная статья поможет вам в работе и сделает ваше понимание списков чуть лучше :).

Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Artem Rovenskii. List in C#: implementation and features.

Коллекции

Последнее обновление: 03.01.2022

Хотя в языке C# есть массивы, которые хранят в себе наборы однотипных объектов, но работать с ними не всегда удобно. Например, массив хранит
фиксированное количество объектов, однако что если мы заранее не знаем, сколько нам потребуется объектов. И в этом случае намного удобнее применять
коллекции. Еще один плюс коллекций состоит в том, что некоторые из них реализует стандартные структуры данных, например, стек, очередь, словарь, которые
могут пригодиться для решения различных специальных задач. Большая часть классов коллекций содержится в пространстве имен
System.Collections.Generic.

Класс List<T> из пространства имен System.Collections.Generic представляет простейший список однотипных объектов. Класс List типизируется типом, объекты которого будут хранится в списке.

Мы можем создать пустой список:

List<string> people = new List<string>();

В данном случае объект List типизируется типом string. А это значит, что хранить в этом списке мы можем только строки.

Можно сразу при создании списка инициализировать его начальными значениями. В этом случае элементы списка помещаются после вызова конструктора в фигурных скобках

List<string> people = new List<string>() { "Tom", "Bob", "Sam" };

В данном случае в список помещаются три строки

Также можно при создании списка инициализировать его элементами из другой коллекции, например, другого списка:

var people = new List<string>() { "Tom", "Bob", "Sam" };
var employees = new List<string>(people);

Можно совместить оба способа:

var people = new List<string>() { "Tom", "Bob", "Sam" };
var employees = new List<string>(people){"Mike"};

В данном случае в списке employees будет четыре элемента ({ "Tom", "Bob", "Sam", "Mike" }) — три добавляются из списка people и один элемент задается при инициализации.

Подобным образом можно работать со списками других типов, например:

List<Person> people = new List<Person>() 
{ 
    new Person("Tom"),
    new Person("Bob"), 
    new Person("Sam") 
};

class Person
{
    public string Name { get;}
    public Person(string name) => Name = name;
}

Установка начальной емкости списка

Еще один конструктор класса List принимает в качестве параметра начальную емкость списка:

List<string> people = new List<string>(16);

Указание начальной емкости списка позволяет в будущем увеличить производительность и уменьшить издержки на выделение памяти при
добавлении элементов. Поскольку динамическое добавление в список может приводить на низком уровне к дополнительному выделению памяти, что
снижает производительность. Если же мы знаем, что список не будет превышать некоторый размер, то мы можем передать этот размер в качестве емкости списка и
избежать дополнительных выделений памяти.

Также начальную емкость можно установить с помощью свойства Capacity, которое имеется у класса List.

Обращение к элементам списка

Как и массивы, списки поддерживают индексы, с помощью которых можно обратиться к определенным элементам:

var people = new List<string>() { "Tom", "Bob", "Sam" };

string firstPerson = people[0];	// получаем первый элемент
Console.WriteLine(firstPerson); // Tom
people[0] = "Mike";		// изменяем первый элемент
Console.WriteLine(people[0]); // Mike

Длина списка

С помощью свойства Count можно получить длину списка:

var people = new List<string>() { "Tom", "Bob", "Sam" };
Console.WriteLine(people.Count);    // 3

Перебор списка

C# позволяет осуществить перебор списка с помощью стандартного цикла foreach:/p>

var people = new List<string>() { "Tom", "Bob", "Sam" };

foreach (var person in people)
{
    Console.WriteLine(person);
}
// Вывод программы:
// Tom
// Bob
// Sam

Также можно использовать другие типы циклов и в комбинации с индексами перебирать списки:

var people = new List<string>() { "Tom", "Bob", "Sam" };

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

Методы списка

Среди его методов можно выделить следующие:

  • void Add(T item): добавление нового элемента в список

  • void AddRange(IEnumerable<T> collection): добавление в список коллекции или массива

  • int BinarySearch(T item): бинарный поиск элемента в списке. Если элемент найден, то метод возвращает индекс этого элемента в коллекции.
    При этом список должен быть отсортирован.

  • void CopyTo(T[] array): копирует список в массив array

  • void CopyTo(int index, T[] array, int arrayIndex, int count): копирует из списка начиная с индекса index элементы,
    количество которых равно count, и вставляет их в массив array начиная с индекса arrayIndex

  • bool Contains(T item): возвращает true, если элемент item есть в списке

  • void Clear(): удаляет из списка все элементы

  • bool Exists(Predicate<T> match): возвращает true, если в списке есть элемент, который
    соответствует делегату match

  • T? Find(Predicate<T> match): возвращает первый элемент, который соответствует делегату match. Если элемент не найден, возвращается null

  • T? FindLast(Predicate<T> match): возвращает последний элемент, который соответствует делегату match. Если элемент не найден, возвращается null

  • List<T> FindAll(Predicate<T> match): возвращает список элементов, которые соответствуют делегату match

  • int IndexOf(T item): возвращает индекс первого вхождения элемента в списке

  • int LastIndexOf(T item): возвращает индекс последнего вхождения элемента в списке

  • List<T> GetRange(int index, int count): возвращает список элементов, количество которых равно count, начиная
    с индекса index.

  • void Insert(int index, T item): вставляет элемент item в список по индексу index. Если такого индекса в списке нет, то генерируется исключение

  • void InsertRange(int index, collection): вставляет коллекцию элементов collection в текущий список начиная с индекса index. Если такого индекса в списке нет, то генерируется исключение

  • bool Remove(T item): удаляет элемент item из списка, и если удаление прошло успешно, то возвращает true. Если в списке несколько одинаковых элементов,
    то удаляется только первый из них

  • void RemoveAt(int index): удаление элемента по указанному индексу index. Если такого индекса в списке нет, то генерируется исключение

  • void RemoveRange(int index, int count): параметр index задает индекс, с которого надо удалить элементы, а параметр
    count задает количество удаляемых элементов.

  • int RemoveAll((Predicate<T> match)): удаляет все элементы, которые соответствуют делегату match. Возвращает
    количество удаленных элементов

  • void Reverse(): изменяет порядок элементов

  • void Reverse(int index, int count): изменяет порядок на обратный для элементов, количество которых равно count, начиная с индекса index

  • void Sort(): сортировка списка

  • void Sort(IComparer<T>? comparer): сортировка списка с помощью объекта comparer, который передается в качестве параметра

Добавление в список

List people = new List () { "Tom" };

people.Add("Bob"); // добавление элемента
// people = { "Tom", "Bob" };

people.AddRange(new[] { "Sam", "Alice" });   // добавляем массив
// people = { "Tom", "Bob", "Sam", "Alice" };
// также можно было бы добавить другой список
// people.AddRange(new List<string>(){ "Sam", "Alice" });

people.Insert(0, "Eugene"); // вставляем на первое место
// people = { "Eugene", "Tom", "Bob", "Sam", "Alice" };

people.InsertRange(1, new string[] {"Mike", "Kate"}); // вставляем массив с индекса 1
// people = { "Eugene", "Mike", "Kate", "Tom", "Bob", "Sam", "Alice" };

// также можно было бы добавить другой список
// people.InsertRange(1, new List<string>(){ "Mike", "Kate" });

Удаление из списка

var people = new List<string> () { "Eugene", "Mike", "Kate", "Tom", "Bob", "Sam", "Tom", "Alice" };

people.RemoveAt(1); //  удаляем второй элемент
// people = { "Eugene", "Kate", "Tom", "Bob", "Sam", "Tom", "Alice" };

people.Remove("Tom"); //  удаляем элемент "Tom"
// people = { "Eugene", "Kate", "Bob", "Sam", "Tom", "Alice" };

// удаляем из списка все элементы, длина строки которых равна 3
people.RemoveAll(person => person.Length == 3);
// people = { "Eugene", "Kate", "Alice" };

// удаляем из списка 2 элемента начиная с индекса 1
people.RemoveRange(1, 2);
// people = { "Eugene"};

// полностью очищаем список
people.Clear();
// people = {  };

Поиск и проверка элемента

var people = new List<string> () { "Eugene", "Mike", "Kate", "Tom", "Bob", "Sam" };

var containsBob = people.Contains("Bob");     //  true
var containsBill = people.Contains("Bill");    // false

// проверяем, есть ли в списке строки с длиной 3 символа
var existsLength3 = people.Exists(p => p.Length == 3);  // true

// проверяем, есть ли в списке строки с длиной 7 символов
var existsLength7 = people.Exists(p => p.Length == 7);  // false

// получаем первый элемент с длиной в 3 символа
var firstWithLength3 = people.Find(p => p.Length == 3); // Tom

// получаем последний элемент с длиной в 3 символа
var lastWithLength3 = people.FindLast(p => p.Length == 3);  // Sam

// получаем все элементы с длиной в 3 символа в виде списка
List<string> peopleWithLength3 = people.FindAll(p => p.Length == 3);
// peopleWithLength3 { "Tom", "Bob", "Sam"}

Получение диапазона и копирование в массив

List<string> people = new List<string>() {"Eugene", "Tom", "Mike", "Sam", "Bob" };

// получаем диапазон со второго по четвертый элемент
var range = people.GetRange(1, 3);
// range = { "Tom", "Mike", "Sam"};

// копируем в массив первые три элемента
string[] partOfPeople = new string[3];
people.CopyTo(0, partOfPeople, 0, 3);
// partOfPeople = { "Eugene", "Tom", "Mike"};

Расположение элементов в обратном порядке

var people = new List<string> () { "Eugene", "Tom", "Mike", "Sam", "Bob" };

// переворачиваем весь список
people.Reverse();
// people = { "Bob","Sam", "Mike", "Tom", "Eugene"};

var people2 = new List<string>() { "Eugene", "Tom", "Mike", "Sam", "Bob" };
// переворачиваем часть только 3 элемента с индекса 1
people2.Reverse(1, 3);
// people2 = { "Eugene","Sam", "Mike", "Tom", "Bob" };

Коллекции являются одним из наиболее часто используемых инструментов в разработке программного обеспечения. В этом уроке мы познакомимся с пространством имен System.Collections.Generic, коллекциями List, Dictionary и типом Tuple.

  • Что такое коллекции?
  • Коллекции в языке C#. Пространство имен System.Collections.Generic
    • Списки List
    • Словари Dictionary
  • Кортежи Tuple

Исходный код примеров из этой статьи можете скачать из нашего github-репозитория.

Коллекции

Самым примитивным способом хранения объектов в C# является использование массивов. Одной из основных проблем, с которой столкнется разработчик следуя такому подходу, является то, что массивы не предоставляют инструментов для динамического изменения размера. В языке C# есть два пространства имен для работы со структурами данных:

  • System.Collections;
  • System.Collections.Generic.

Первое из них – System.Collections предоставляет структуры данных для хранения объектов типа Object. У этого решения есть две основных проблемы – это производительность и безопасность типов. В настоящее время не рекомендуется использовать объекты классов из System.Collections

Для решения указанных выше проблем Microsoft были разработаны коллекции с обобщенными типами (их ещё называют дженерики), они расположены в пространстве  имен System.Collections.Generic. Суть их заключается в том, что вы не просто создает объект класса List, но и указываете, объекты какого типа будут в нем храниться, делается это так: List<T>, где T может быть int, string, double или какой-то ваш собственный класс. 

В рамках данного урока мы не будем подробно останавливаться на особенностях обобщенных типов, на текущий момент можете их воспринимать как псевдонимы, для реальных типов данных. 

Коллекции в языке C#. Пространство имен System.Collections.Generic

Пространство System.Collections.Generic содержит большой набор коллекций, которые позволяют удобно и эффективно решать широкий круг задач. Ниже, в таблице, перечислены некоторые из обобщенных классов с указанием интерфейсов, которые они реализуют.

Обобщенный класс Основные интерфейсы Описание
List<T> ICollection<T>, IEnumerable<T>, IList<T> Список элементов с динамически изменяемым размером
Dictionary<TKey, TValue> ICollection<T>, IDictionary<TKey, TValue>,

IEnumerable<T>

Коллекция элементов связанных через уникальный ключ
Queue<T> ICollection, IEnumerable<T> Очередь –  список, работающий по алгоритму FIFO
Stack<T> ICollection, IEnumerable<T> Стэк – список, работающий по алгоритму LIFO
SortedList<TKey,TValue> IComparer<T>, ICollection<KeyValuePair<TKey,TValue>>, IDictionary<TKey,TValue> Коллекция пар “ключ-значение”, упорядоченных по ключу

Познакомимся поближе с несколькими классами из приведенной таблицы.

Класс List<T>

Начнем наше знакомство с коллекциями с класса List<T>. Эта коллекция является аналогом типизированного массива, который может динамически расширяться. В качестве типа можно указать любой встроенный либо пользовательский тип.

Создание объекта класса List<T>

Можно создать пустой список и добавить в него элементы позже, с помощью метода Add():

List<int> numsList = new List<int>();
numsList.Add(1);

Либо воспользоваться синтаксисом, позволяющем указать набор объектов, который будет храниться в списке:

List<int> nums = new List<int> {1, 2, 3, 4, 5};
var words = new List<string> {"one", "two", "three"};

Работа с объектами List<T>

Ниже приведены таблицы, в которых перечислены некоторые полезные свойства и методы класса List<T>. Более подробную информацию по методам и свойствам List<T> вы можете найти в официальной документации.

Свойства класса List<T>

Свойство Описание
Count Количество элементов в списке
Capacity Емкость списка – количество элементов, которое может вместить список без изменения размера
Console.WriteLine("Свойства");
Console.WriteLine($"- Count: nums.Count = {nums.Count}");
Console.WriteLine($"- Capacity: nums.Capacity = {nums.Capacity}");

Методы класса List<T>

Метод Описание
Add(T) Добавляет элемент к списку
BinarySearch(T) Выполняет поиск по списку
Clear() Очистка списка
Contains(T) Возвращает true, если список содержит указанный элемент
IndexOf(T) Возвращает индекс переданного элемента
ForEach(Action<T>) Выполняет указанное действие для всех элементов списка
Insert(Int32, T) Вставляет элемент в указанную позицию
Find(Predicate<T>) Осуществляет поиск первого элемент, для которого выполняется заданный предикат
Remove(T) Удаляет указанный элемент из списка
RemoveAt(Int32) Удаляет элемент из заданной позиции
Sort() Сортирует список
Reverse() Меняет порядок расположения элементов на противоположный
Console.WriteLine($"nums: {ListToString(nums)}");            
nums.Add(6);
Console.WriteLine($"nums.Add(6): {ListToString(nums)}");            
Console.WriteLine($"words.BinarySearch("two"): {words.BinarySearch("two")}");
Console.WriteLine($"nums.Contains(10): {nums.Contains(10)}");
Console.WriteLine($"words.IndexOf("three"): {words.IndexOf("three")}");
Console.WriteLine($"nums.ForEach(v => v * 10)");
nums.ForEach(v => Console.Write($"{v} => "));            
nums.Insert(3, 7);
Console.WriteLine($"nums.Insert(3, 7): {ListToString(nums)}");
Console.WriteLine($"words.Find(v => v.Length == 3): {words.Find(v => v.Length == 3)}");
words.Remove("two");
Console.WriteLine($"words.Remove("two"): {ListToString(words)}");

Код метода ListToString:

static private string ListToString<T>(List<T> list) =>
"{" + string.Join(", ", list.ToArray()) + "}";

Далее приведен пример работы со списком, в котором хранятся объекты пользовательского типа. Создадим класс Player, имеющий свойства: Name и Skill.

class Player
{
    public string Name { get; set; }
    public string Skill { get; set; }
}

Создадим список игроков и выполним с ним ряд действий:

Console.WriteLine("Работа с пользовательским типом");
List<Player> players = new List<Player> {
    new Player { Name = "Psy", Skill = "Monster"},
    new Player { Name = "Kubik", Skill = "Soldier"},
    new Player { Name = "Triver", Skill = "Middle"},
    new Player { Name = "Terminator", Skill = "Very High"}
};
Console.WriteLine("Количество элементов в players:{0}", players.Count);
//Добавим новый элемент списка players
players.Insert(1, new Player { Name = "Butterfly", Skill = "flutter like a butterfly, pity like a bee"});
//Посмотрим на все элементы списка
players.ForEach(p => Console.WriteLine($"{p.Name}, skill: {p.Skill}"));

Класс Dictionary<TKey,TValue>

Класс Dictionary реализует структуру данных Отображение, которую иногда называют Словарь или Ассоциативный массив. Идея довольно проста: в обычном массиве доступ к данным мы получаем через целочисленный индекс, в словаре используется ключ, который может быть числом, строкой или любым другим типом данных, который реализует метод GetHashCode(). При добавлении нового объекта в такую коллекцию для него указывается уникальный ключ, который используется для последующего доступа к нему.

Создание объекта класса Dictionary

Пустой словарь:

var dict = new Dictionary<string, int>();

Словарь с набором элементов:

var prodPrice = new Dictionary<string, double>() 
{
    ["bread"] = 23.3,
    ["apple"] = 45.2
};
Console.WriteLine($"bread price: {prodPrice["bread"]}");

Работа с объектами Dictionary

Рассмотрим некоторые из свойств и методов класса Dictionary<TKey, TValue>. Полное описание возможностей этого класса вы можете найти на официальной странице Microsoft.

Свойства класса Dictionary

Свойство Описание
Count Количество объектов в словаре
Keys Ключи словаря
Values Значения элементов словаря
Console.WriteLine("Свойства");
Console.WriteLine($"Словарь prodPrice: {DictToString(prodPrice)}");
Console.WriteLine($"Count: {prodPrice.Count}");
Console.WriteLine($"Keys: {ListToString(prodPrice.Keys.ToList<string>())}");
Console.WriteLine($"Values: {ListToString(prodPrice.Values.ToList<double>())}");

Методы класса Dictionary

Метод Описание
Add(TKey, TValue) Добавляет в словарь элемент с заданным ключом и значением
Clear() Удаляет из словаря все ключи и значения
ContainsValue(TValue) Проверяет наличие в словаре указанного значения
ContainsKey(TKey) Проверяет наличие в словаре указанного ключа
GetEnumerator() Возвращает перечислитель для перебора элементов словаря
Remove(TKey) Удаляет элемент с указанным ключом
TryAdd(TKey, TValue) Метод, реализующий попытку добавить в словарь элемент с заданным ключом и значением
TryGetValue(TKey, TValue) Метод, реализующий попытку получить значение по заданному ключу
prodPrice.Add("tomate", 11.2);
Console.WriteLine($"Словарь prodPrice: {DictToString(prodPrice)}");
var isExistValue = prodPrice.ContainsValue(11.2);
Console.WriteLine($"isExistValue = {isExistValue}");
var isExistKey = prodPrice.ContainsKey("tomate");
Console.WriteLine($"isExistKey = {isExistKey}");
prodPrice.Remove("bread");
Console.WriteLine($"Словарь prodPrice: {DictToString(prodPrice)}");
var isOrangeAdded = prodPrice.TryAdd("orange", 20.1);
Console.WriteLine($"isOrangeAdded = {isOrangeAdded}");
double orangePrice;
var isPriceGetted = prodPrice.TryGetValue("orange", out orangePrice);
Console.WriteLine($"isPriceGetted = {isPriceGetted}");
Console.WriteLine($"orangePrice = {orangePrice}");
prodPrice.Clear();
Console.WriteLine($"Словарь prodPrice: {DictToString(prodPrice)}");

Кортежи Tuple и ValueTuple

Относительно недавним нововведением в языке C# (начиная с C# 7) являются кортежи. Кортежем называют структуру данных типа Tuple или ValueTuple (чуть ниже мы рассмотрим различия между ними), которые позволяют группировать объекты разных типов друг с другом. С практической точки зрения они являются удобным способом возврата из метода нескольких значений – это наиболее частый вариант использования кортежей.

Различия между Tuple и ValueTuple приведены в таблице ниже.

Tuple  ValueTuple 
Ссылочный тип Тип значение
Неизменяемый тип Изменяемый тип
Элементы данных – это свойства Элементы данных – это поля

Создание кортежей

Рассмотрим несколько вариантов создания кортежей.

Создание кортежа без явного и с явным указанием имен полей:

(string, int) p1 = ("John", 21);
(string Name, int Age) p2 = ("Mary", 23);

При этом для доступа к элементам кортежа в первом варианте используются свойства Item с числом, указывающем на порядок элемента, во втором – заданные пользователем имена:

Console.WriteLine($"p1: Name: {p1.Item1}, Age: {p1.Item2}");
Console.WriteLine($"p1: Name: {p2.Name}, Age: {p2.Age}");

Возможны следующие способы создания кортежей с явным заданием имен:

var p3 = (Name: "Alex", Age: 24);
var Name = "Lynda";
var Age = 25;
var p4 = (Name, Age);
Console.WriteLine($"p3: Name: {p3.Name}, Age: {p3.Age}");
Console.WriteLine($"p4: Name: {p4.Name}, Age: {p4.Age}");

При этом возможность обращаться через свойства Item1 и Item2 для созданных выше переменных остается:

Console.WriteLine($"p3: Name: {p3.Item1}, Age: {p3.Item2}");
Console.WriteLine($"p4: Name: {p4.Item1}, Age: {p4.Item2}");

Работа с кортежами

Как было сказано в начале раздела, кортежи можно возвращать в качестве результата работы метода. Пример метода, который сравнивает длину переданной строки с некоторым порогом и возвращает соответствующее bool-значение и целое число – длину строки:

static (bool isLonger, int count) LongerThenLimit(string str, int limit) =>
str.Length > limit ? (true, str.Length) : (false, str.Length);

Кортежи можно присваивать друг другу, при этом необходимо, чтобы соблюдались следующие условия:

  • количество элементов  в обоих кортежах одинаковое;
  • типы соответствующих элементов совпадают, либо могут быть приведены друг к другу.
var p5 = ("Jane", 26);
(string, int) p6 = p5;
Console.WriteLine($"p6: Name: {p6.Item1}, Age: {p6.Item2}");

Операцию присваивания можно использовать для деструкции кортежа. 

(string name, int age) = p5;
Console.WriteLine($"Name: {name}, Age: {age}");

Исходный код примеров из этой статьи можете скачать из нашего github-репозитория.

Improve Article

Save Article

  • Read
  • Discuss
  • Improve Article

    Save Article

    List<T> class represents the list of objects which can be accessed by index. It comes under the System.Collections.Generic namespace. List class can be used to create a collection of different types like integers, strings etc. List<T> class also provides the methods to search, sort, and manipulate lists.

    Characteristics:

    • It is different from the arrays. A List<T> can be resized dynamically but arrays cannot.
    • List<T> class can accept null as a valid value for reference types and it also allows duplicate elements.
    • If the Count becomes equals to Capacity, then the capacity of the List increased automatically by reallocating the internal array. The existing elements will be copied to the new array before the addition of the new element.
    • List<T> class is the generic equivalent of ArrayList class by implementing the IList<T> generic interface.
    • This class can use both equality and ordering comparer.
    • List<T> class is not sorted by default and elements are accessed by zero-based index.
    • For very large List<T> objects, you can increase the maximum capacity to 2 billion elements on a 64-bit system by setting the enabled attribute of the configuration element to true in the run-time environment.

    Constructors

    Constructor Description
    List<T>() Initializes a new instance of the List<T> class that is empty and has the default initial capacity.
    List<T>(IEnumerable<T>) Initializes a new instance of the List<T> class that contains elements copied from the specified collection and has sufficient capacity to accommodate the number of elements copied.
    List<T>(Int32) Initializes a new instance of the List<T> class that is empty and has the specified initial capacity.

    Example:

    using System;

    using System.Collections.Generic;

    class Geeks {

        public static void Main(String[] args)

        {

            List<int> firstlist = new List<int>();

            Console.WriteLine(firstlist.Count);

        }

    }

    Output:

    0
    

    Properties

    Property Description
    Capacity Gets or sets the total number of elements the internal data structure can hold without resizing.
    Count Gets the number of elements contained in the List<T>.
    Item[Int32] Gets or sets the element at the specified index.

    Example:

    using System;

    using System.Collections.Generic;

    class Geeks {

        public static void Main(String[] args)

        {

            List<int> firstlist = new List<int>();

            firstlist.Add(1);

            firstlist.Add(2);

            firstlist.Add(3);

            firstlist.Add(4);

            Console.WriteLine("Capacity Is: " + firstlist.Capacity);

            Console.WriteLine("Count Is: " + firstlist.Count);

            firstlist.Add(5);

            firstlist.Add(6);

            Console.WriteLine("Capacity Is: " + firstlist.Capacity);

            Console.WriteLine("Count Is: " + firstlist.Count);

        }

    }

    Output:

    Capacity Is: 4
    Count Is: 4
    Capacity Is: 8
    Count Is: 6
    

    Methods

    Method Description
    Add(T) Adds an object to the end of the List<T>.
    AddRange(IEnumerable<T>) Adds the elements of the specified collection to the end of the List<T>.
    AsReadOnly() Returns a read-only ReadOnlyCollection<T> wrapper for the current collection.
    BinarySearch() Uses a binary search algorithm to locate a specific element in the sorted List<T> or a portion of it.
    Clear() Removes all elements from the List<T>.
    Contains(T) Determines whether an element is in the List<T>.
    ConvertAll(Converter) Converts the elements in the current List<T> to another type, and returns a list containing the converted elements.
    CopyTo() Copies the List<T> or a portion of it to an array.
    Equals(Object) Determines whether the specified object is equal to the current object.
    Exists(Predicate<T>) Determines whether the List<T> contains elements that match the conditions defined by the specified predicate.
    Find(Predicate<T>) Searches for an element that matches the conditions defined by the specified predicate, and returns the first occurrence within the entire List<T>.
    FindAll(Predicate<T>) Retrieves all the elements that match the conditions defined by the specified predicate.
    FindIndex() Searches for an element that matches the conditions defined by a specified predicate, and returns the zero-based index of the first occurrence within the List<T> or a portion of it. This method returns -1 if an item that matches the conditions is not found.
    FindLast(Predicate<T>) Searches for an element that matches the conditions defined by the specified predicate, and returns the last occurrence within the entire List<T>.
    FindLastIndex() Searches for an element that matches the conditions defined by a specified predicate, and returns the zero-based index of the last occurrence within the List<T> or a portion of it.
    ForEach(Action<T>) Performs the specified action on each element of the List<T>.
    GetEnumerator() Returns an enumerator that iterates through the List<T>.
    GetHashCode() Serves as the default hash function.
    GetRange(Int32, Int32) Creates a shallow copy of a range of elements in the source List<T>.
    GetType() Gets the Type of the current instance.
    IndexOf() Returns the zero-based index of the first occurrence of a value in the List<T> or in a portion of it.
    Insert(Int32, T) Inserts an element into the List<T> at the specified index.
    InsertRange(Int32, IEnumerable<T>) Inserts the elements of a collection into the List<T> at the specified index.
    LastIndexOf() Returns the zero-based index of the last occurrence of a value in the List<T> or in a portion of it.
    MemberwiseClone() Creates a shallow copy of the current Object.
    Remove(T) Removes the first occurrence of a specific object from the List<T>.
    RemoveAll(Predicate<T>) Removes all the elements that match the conditions defined by the specified predicate.
    RemoveAt(Int32) Removes the element at the specified index of the List<T>.
    RemoveRange(Int32, Int32) Removes a range of elements from the List<T>.
    Reverse() Reverses the order of the elements in the List<T> or a portion of it.
    Sort() Sorts the elements or a portion of the elements in the List<T> using either the specified or default IComparer<T> implementation or a provided Comparison<T> delegate to compare list elements.
    ToArray() Copies the elements of the List<T> to a new array.
    ToString() Returns a string that represents the current object.
    TrimExcess() Sets the capacity to the actual number of elements in the List<T>, if that number is less than a threshold value.
    TrueForAll(Predicate<T>) Determines whether every element in the List<T> matches the conditions defined by the specified predicate.

    Example 1:

    using System;

    using System.Collections.Generic;

    class Geeks {

        public static void Main(String[] args)

        {

            List<int> firstlist = new List<int>();

            firstlist.Add(1);

            firstlist.Add(2);

            firstlist.Add(3);

            firstlist.Add(4);

            firstlist.Add(5);

            firstlist.Add(6);

            firstlist.Add(7);

            Console.Write(firstlist.Contains(4));

        }

    }

    Output:

    True
    

    Example 2:

    using System;

    using System.Collections.Generic;

    class Geeks {

        public static void Main(String[] args)

        {

            List<int> firstlist = new List<int>();

            firstlist.Add(17);

            firstlist.Add(19);

            firstlist.Add(21);

            firstlist.Add(9);

            firstlist.Add(75);

            firstlist.Add(19);

            firstlist.Add(73);

            Console.WriteLine("Elements Present in List:n");

            int p = 0;

            foreach(int k in firstlist)

            {

                Console.Write("At Position {0}: ", p);

                Console.WriteLine(k);

                p++;

            }

            Console.WriteLine(" ");

            Console.WriteLine("Removing the element at index 3n");

            firstlist.RemoveAt(3);

            int p1 = 0;

            foreach(int n in firstlist)

            {

                Console.Write("At Position {0}: ", p1);

                Console.WriteLine(n);

                p1++;

            }

        }

    }

    Output:

    Elements Present in List:
    
    At Position 0: 17
    At Position 1: 19
    At Position 2: 21
    At Position 3: 9
    At Position 4: 75
    At Position 5: 19
    At Position 6: 73
     
    Removing the element at index 3
    
    At Position 0: 17
    At Position 1: 19
    At Position 2: 21
    At Position 3: 75
    At Position 4: 19
    At Position 5: 73
    

    Reference:

    • https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1?view=netframework-4.7.2

    The List<T> is a collection of strongly typed objects that can be accessed by index and having methods for sorting, searching, and modifying list.
    It is the generic version of the ArrayList that comes under System.Collections.Generic namespace.

    List<T> Characteristics

    • List<T> equivalent of the ArrayList, which implements IList<T>.
    • It comes under System.Collections.Generic namespace.
    • List<T> can contain elements of the specified type. It provides compile-time type checking and doesn’t perform boxing-unboxing because it is generic.
    • Elements can be added using the Add(), AddRange() methods or collection-initializer syntax.
    • Elements can be accessed by passing an index e.g. myList[0]. Indexes start from zero.
    • List<T> performs faster and less error-prone than the ArrayList.

    Creating a List

    The List<T> is a generic collection, so you need to specify a type parameter for the type of data it can store.
    The following example shows how to create list and add elements.

    List<int> primeNumbers = new List<int>();
    primeNumbers.Add(1); // adding elements using add() method
    primeNumbers.Add(3);
    primeNumbers.Add(5);
    primeNumbers.Add(7);
    
    var cities = new List<string>();
    cities.Add("New York");
    cities.Add("London");
    cities.Add("Mumbai");
    cities.Add("Chicago");
    cities.Add(null);// nulls are allowed for reference type list
    
    //adding elements using collection-initializer syntax
    var bigCities = new List<string>()
                        {
                            "New York",
                            "London",
                            "Mumbai",
                            "Chicago"                    
                        };
    

    In the above example, List<int> primeNumbers = new List<int>(); creates a list of int type.
    In the same way, cities and bigCities are string type list.
    You can then add elements in a list using the Add() method or the collection-initializer syntax.

    You can also add elements of the custom classes using the collection-initializer syntax.
    The following adds objects of the Student class in the List<Student>.

    var students = new List<Student>() { 
                    new Student(){ Id = 1, Name="Bill"},
                    new Student(){ Id = 2, Name="Steve"},
                    new Student(){ Id = 3, Name="Ram"},
                    new Student(){ Id = 4, Name="Abdul"}
                };
    

    Adding an Array in a List

    Use the AddRange() method to add all the elements from an array or another collection to List.

    AddRange() signature: void AddRange(IEnumerable<T> collection)

    string[] cities = new string[3]{ "Mumbai", "London", "New York" };
    
    var popularCities = new List<string>();
    
    // adding an array in a List
    popularCities.AddRange(cities);
    
    var favouriteCities = new List<string>();
    
    // adding a List 
    favouriteCities.AddRange(popularCities);
    

    Accessing a List

    A list can be accessed by an index, a for/foreach loop, and using LINQ queries.
    Indexes of a list start from zero. Pass an index in the square brackets to access individual list items, same as array.
    Use a foreach or for loop to iterate a List<T> collection.

    List<int> numbers = new List<int>() { 1, 2, 5, 7, 8, 10 };
    Console.WriteLine(numbers[0]); // prints 1
    Console.WriteLine(numbers[1]); // prints 2
    Console.WriteLine(numbers[2]); // prints 5
    Console.WriteLine(numbers[3]); // prints 7
    
    // using foreach LINQ method
    numbers.ForEach(num => Console.WriteLine(num + ", "));//prints 1, 2, 5, 7, 8, 10,
    
    // using for loop
    for(int i = 0; i < numbers.Count; i++)
        Console.WriteLine(numbers[i]);
    

    Accessing a List using LINQ

    The List<T> implements the IEnumerable interface. So, we can query a list using LINQ query syntax or method syntax, as shown below.

    var students = new List<Student>() { 
                    new Student(){ Id = 1, Name="Bill"},
                    new Student(){ Id = 2, Name="Steve"},
                    new Student(){ Id = 3, Name="Ram"},
                    new Student(){ Id = 4, Name="Abdul"}
                };
    
    //get all students whose name is Bill
    var result = from s in students
    	     where s.Name == "Bill"
    	     select s;
    		
    foreach(var student in result)
        Console.WriteLine(student.Id + ", " + student.Name);
    

    Insert Elements in List

    Use the Insert() method inserts an element into the List<T> collection at the specified index.

    Insert() signature:void Insert(int index, T item);

    var numbers = new List<int>(){ 10, 20, 30, 40 };
    
    numbers.Insert(1, 11);// inserts 11 at 1st index: after 10.
    
    foreach (var num in numbers)
        Console.Write(num);
    

    Remove Elements from List

    Use the Remove() method to remove the first occurrence of the specified element in the List<T> collection.
    Use the RemoveAt() method to remove an element from the specified index. If no element at the specified index, then the ArgumentOutOfRangeException will be thrown.

    Remove() signature: bool Remove(T item)

    RemoveAt() signature: void RemoveAt(int index)

    var numbers = new List<int>(){ 10, 20, 30, 40, 10 };
    
    numbers.Remove(10); // removes the first 10 from a list
    
    numbers.RemoveAt(2); //removes the 3rd element (index starts from 0)
    
    //numbers.RemoveAt(10); //throws ArgumentOutOfRangeException
    
    foreach (var el in intList)
        Console.Write(el); //prints 20 30
    

    Check Elements in List

    Use the Contains() method to determine whether an element is in the List<T> or not.

    var numbers = new List<int>(){ 10, 20, 30, 40 };
    numbers.Contains(10); // returns true
    numbers.Contains(11); // returns false
    numbers.Contains(20); // returns true
    

    List<T> Class Hierarchy

    The following diagram illustrates the List<T> hierarchy.

    List<T> Hierarchy

    List<T> Class Properties and Methods

    The following table lists the important properties and methods of List<T> class:

    Property Usage
    Items Gets or sets the element at the specified index
    Count Returns the total number of elements exists in the List<T>
    Method Usage
    Add Adds an element at the end of a List<T>.
    AddRange Adds elements of the specified collection at the end of a List<T>.
    BinarySearch Search the element and returns an index of the element.
    Clear Removes all the elements from a List<T>.
    Contains Checks whether the specified element exists or not in a List<T>.
    Find Finds the first element based on the specified predicate function.
    Foreach Iterates through a List<T>.
    Insert Inserts an element at the specified index in a List<T>.
    InsertRange Inserts elements of another collection at the specified index.
    Remove Removes the first occurrence of the specified element.
    RemoveAt Removes the element at the specified index.
    RemoveRange Removes all the elements that match the supplied predicate function.
    Sort Sorts all the elements.
    TrimExcess Sets the capacity to the actual number of elements.
    TrueForAll Determines whether every element in the List<T>
    matches the conditions defined by the specified predicate.

    The objective of this article is to familiarize you with the generic C# List, which is implemented via List<T> collection class. You will learn how to declare, create, instantiate and use this type of collection, including code examples of the commonly used methods and properties of List<> class. Finally, different ways to iterate through all the items of the collection.

    Table of Contents
    • What is the list in C#?
    • Common Properties and Methods of the List<> Class
    • using Statement
    • How do you create a list in C#?
    • C# Collection Initializers
    • Add Items to a C# List
      • Add()
      • AddRange()
      • Insert()
      • InsertRange()
    • Remove Items from a C# List
      • Remove()
      • RemoveAt()
      • RemoveRange()
      • Clear()
    • C# List Methods
      • Contains()
      • Sort()
      • TrimExcess()
    • C# List Properties
      • Count
      • Count()
      • Capacity
    • Access Individual List Item
    • Processing C# List With Loops
      • for Loop
      • foreach Loop
      • ForEach Loop
    • Processing C# List with LINQ
    • C# List Examples

    What Is the List in C#?

    The generic List<T> class is the simplest of the collection classes defined by the .NET Framework. The first thing to understand is that the C# List is a simple ordered list of items that has the ability to store any type of object, just like an array. Also, like an array, you must specify which type of object you want a particular List to store. This means that if you want a List of integers of the int data type then you can create a List that will store only the int type.

    For resizable lists, .NET offers the generic class List<T>. This class implements the IList, ICollection, IEnumerable, IList<T>, ICollection<T>, and IEnumerable<T> interfaces.


    Properties and Methods of C# List Class

    C# List class provides several methods for manipulating the items it contains. The following is list of some frequently used properties and methods defined in a List<T>.

    C# List

    You can declare and initialize C# List as in the following code.

    using Statement

    To work with the C# List, you need to add the following namespace at the beginning your code:

    using System.Collections.Generic;

    How Do You Create a List in C#?

    You can create C# List using either one or two statements.

    Declare and Initialize C# List Using Two Statements

    The T part of the declaration indicates that the class will work with a certain type. After you finish the declaration, the class knows what data type it will manipulate, and it can behave as if it were designed with that data type in mind.

    List<T> listName; // declaration

    Instead of assigning items in the declaration, you use new keyword with default constructor to initialize an empty List to be stored temporarily in the listName variable. This is how you create an object from the List<> class for a given data type:

    listName = new List<T>(); // initialization

    The default capacity of a list is 0 items, but you can assign a different capacity to create a list. When the number of items in a list exceeds capacity, the list is resized to allow more items. With every resize the capacity is automatically doubled.

    listName = new List<T>(capacity);
    // OR
    listName.Capacity = number;

    The capacity can be decreased by calling TrimExcess method or by setting the Capacity property explicitly.

    Declare and Initialize C# List on a Single Line

    Declaration and initialization of a list at the same time on a single line.

    List<T> listName = new List<T>(); // declaration & initialization

    Use of var keyword with a list to declare a variable that infers its type from the value that’s assigned to it.

    var listName = new List<T>();

    C# Collection Initializers

    You can assign values to collections using collection initializer syntax introduced in C# 3.0. It is a shortened syntax to create an instance of a collection. With a collection initializer, the values can be assigned all at once during the declaration using curly brackets notation. Basically, this is just a shorthand notation for calling Add method multiple times by the compiler.

    Note: The element initializers can be a simple value, an expression or an object initializer.

    List<string> planets = new List<string>() { "Mercury", "Venus", "Earth" };

    If no parameters are passed in the constructor, then parentheses () following the data type are optional.

    List<string> planets = new List<string> { "Mercury", "Venus", "Earth" };

    The following collection C# initializer uses C# object initializers to populate objects of the Planet class. Individual object initializers are enclosed in braces and separated by commas.

    var planets = new List<Planet>
    {
        new Planet() {Id = 1, Name ="Mercury"},
        new Planet() {Id = 2, Name = "Venus"},
        new Planet() {Id = 3, Name = "Earth"}
    };

    Run Demo


    Add Items to a C# List

    List<string> planets = new List<string> { "Mercury", "Venus", "Earth" };
    string[] morePlanets = { "Mars", "Jupiter" };

    Add()

    Add method adds a new item at the end of a list and returns the item’s index. This method checks the capacity of the collection and automatically resize the List, if necessary, easier than adding an item to an array, which requires you to resize the array first.

    Signature: void Add(T item)

    planets.Add("Mars");
    planets.Add("Jupiter");

    Run Demo

    OUTPUT

    Mercury
    Venus
    Earth
    Mars <-
    Jupiter <-

    Using add method to add individual objects of Planet class.

    var planets = new List<Planet>();
    planets.Add(new Planet(){Id =1, Name ="Mercury"});
    planets.Add(new Planet(){Id = 2, Name = "Venus"});
    planets.Add(new Planet(){Id = 3, Name = "Earth"});
    planets.Add(new Planet(){Id =4, Name ="Mars"});

    First, you use new keyword to create a new Planet object, which contains Id and Name property. You set values for the properties one at a time—one per row.

    var jupiter = new Planet();
    jupiter.Id = 5;
    jupiter.Name = "4 line: Jupiter";
    planets.Add(jupiter);

    C# provides a convenient way to set properties, using object initializer syntax. This syntax looks like this:

    //Above 4 lines vs below 1 line syntax. Same result
    planets.Add(new Planet() { Id = 5, Name = "1 line: Jupiter" });

    This frequently used syntax is more readable than the earlier option, where all the properties are set on the same line as the object is created.

    Run Demo

    AddRange()

    You can use the AddRange method of the List<T> class to add multiple items all at once to the end of a collection. You can pass any IEnumerable collection, not just an array or another List.

    Signature: void AddRange(IEnumerable<T> collection)

    planets.AddRange(morePlanets);

    OUTPUT

    Mercury
    Venus
    Earth
    Mars <-
    Jupiter <-

    Run Demo

    Insert()

    You can insert an item at a specific index in the list using the Insert method. The first parameter is the position and the second is the value being inserted. The Exception of type ArgumentOutOfRangeException is thrown, if the index set is larger than the number of items in the collection.

    Signature: void Insert(int index, T item)

    planets.Insert(2, "Mars");

    OUTPUT

    Mercury
    Venus
    Mars <-
    Earth

    Run Demo

    InsertRange()

    The InsertRange method is used to insert multiple items at a specific index in the list. The first parameter is the index position and the second is the collection to be inserted.

    Signature: void InsertRange(int index, IEnumerable<T> collection)

    planets.InsertRange(2, morePlanets);

    OUTPUT

    Mercury
    Venus
    Mars <-
    Jupiter <-
    Earth

    Run Demo


    Remove Items from a C# List

    List<string> planets = new List<string> { "Mercury", "Venus", "Earth", "Mars" };

    Remove()

    The Remove method removes a particular item from the list. This method takes in one argument and removes the first occurrence of that argument. You need to pass the target item, not the index to remove.

    Signature: bool Remove(T item)

    planets.Remove("Venus");

    OUTPUT

    Mercury
    Earth
    Mars

    Run Demo

    RemoveAt()

    The RemoveAt method removes an item from a specific location in the list by passing an index.

    Signature: void RemoveAt(int index)

    planets.RemoveAt(1);

    OUTPUT

    Mercury
    Earth
    Mars

    Run Demo

    RemoveRange()

    The RemoveRange method removes all the items from a particular position in the list. The first parameter is the index, and the second parameter is the total number of items to be removed.

    Signature: void RemoveRange(int index, int count)

    planets.RemoveRange(1, 2);

    OUTPUT

    Mercury
    Mars

    Run Demo

    Clear()

    The Clear method removes all items in a list and sets its Count property to zero.

    Signature: void Clear()

    planets.Clear();

    Run Demo


    C# List Methods

    List<string> planets = new List<string> { "Mercury", "Venus", "Earth" };

    Contains()

    Method checks and returns Boolean (True/False) value if contains the specified item in the list.

    Signature: bool Contains(T item)

    planets.Contains("Venus"); // Returns True

    Run Demo

    Sort()

    Sorts the items in a list into ascending order by calling its Sort method.

    Signature: void Sort()

    planets.Sort();

    OUTPUT

    Earth
    Mercury
    Venus

    Run Demo

    TrimExcess()

    Resizes the capacity to the actual number of items in the List<T>, if that number is less than 90 percent of current capacity.

    Signature: void TrimExcess()

    List<string> planets = new List<string>(6);
    planets.Add("Mercury");
    planets.Add("Venus");
    planets.Add("Earth");
    
    Console.WriteLine($"Capacity : {planets.Capacity}"); // Capacity before TrimExcess() is 6
    
    planets.TrimExcess();
    
    Console.WriteLine($"Capacity : {planets.Capacity}"); // Capacity after TrimExcess() is 3

    Run Demo


    C# List Properties

    List<string> planets = new List<string> { "Mercury", "Venus" };

    Count

    To find out the total number of items in the list, use the Count property (derived from ICollection).

    planets.Count; // Returns 2

    Run Demo

    Count()

    The Count is an extension method introduced by LINQ that loops over all the items in an IEnumerable<> to find the count.

    Required namespace: using System.Linq;

    Signature: int IEnumerable<T>.Count<T>()

    planets.Count(); // Returns 2

    Run Demo

    Capacity

    Gets or sets the number of elements a list can hold, use the Capacity property.

    The default capacity of a list is 0; if initialized as an empty list. As you can see in the following example.

    planets = new List<string>();
    planets.Capacity; // Returns 0

    The capacity automatically assigned to a list is 4, even if initialized with a single item. As soon as the number of items in a list exceeds 4, the list is resized to accommodate more items. With every resizes the capacity is automatically doubled from 4 to 8, 16, 24 etc. Check the below example.

    planets = new List<string> { "Mercury" };
    planets.Capacity; // Returns 4

    If you set the capacity during or after initialization of a list and the number of items exceeds that capacity, an ArgumentOutOfRangeException exception is thrown mentioning ‘capacity was less than the current size.’

    planets = new List<string>() { "Mercury", "Venus", "Earth", "Mars" };
    planets.Capacity = 3; // Set capacity to 3

    Run Demo


    Access Individual List Item

    You can access the list items individually by using an indexer, which must be an integer type. This index position is used inside the square brackets [ ] when retrieving the value from the list. The first item can be accessed with an index value of 0.

    Syntax

    listName[index];
    List<string> planets = new List<string> { "Mercury", "Venus", "Earth" };
    
    planets[1]

    OUTPUT

    Venus

    Run Demo


    Processing C# List With Loops

    The first statement declares a list named planets that contains 3 string values.

    List<string> planets = new List<string> { "Mercury", "Venus", "Earth" };

    Note: It doesn’t matter where you are modifying the collection. If a collection is modified while you are enumerating its members, you get exception.

    for Loop

    Here’s an example that shows how you can create, manipulate, and iterate through the contents of a List<T> collection using C# for loop:

    for (var i = 0; i < planets.Count; i++)
    {
        Console.WriteLine(planets[i]);
    }

    Run Demo

    OUTPUT

    Mercury
    Venus
    Earth

    foreach Loop

    If you use foreach to iterate through a List<T> collection, you cannot use the iteration variable to modify the contents of the collection. Additionally, you cannot call the Remove, Add, or Insert method in a C# foreach loop that iterates through a List<T> collection; any attempt to do so results in an InvalidOperationException exception.

    Note: The foreach statement only allows reading from, not writing to, the collection.

    foreach (var planet in planets)
        Console.WriteLine(planet);

    Run Demo

    OUTPUT

    Mercury
    Venus
    Earth

    ForEach Loop

    Use of ForEach loop to iterate through a List<T> collection.

    planets.ForEach(PrintValue);
    //OR 
    planets.ForEach(planet => Console.WriteLine(planet));
    
    private static void PrintValue(string planet)
    {
        Console.WriteLine(planet);
    }

    Run Demo

    OUTPUT

    Mercury
    Venus
    Earth


    Processing C# List with LINQ

    You can use LINQ to process List collection.

    var planets = new List<Planet>
    {
        new Planet() {Id = 1, Name ="Mercury"},
        new Planet() {Id = 2, Name = "Venus"},
        new Planet() {Id = 3, Name = "Earth"}
    };
    // Namespace required
    using System.Linq;
    // LINQ Method Expression
    var planet = planets.Where(p => p.Id == 2).SingleOrDefault();
    Console.WriteLine($"{planet.Id}, {planet.Name}");
    
    // LINQ Query Expression
    var planet = (from p in planets where p.Id == 3 select p).SingleOrDefault();
    Console.WriteLine($"{planet.Id}, {planet.Name}");

    Run Demo

    OUTPUT

    2, Venus
    3, Earth


    C# List Examples

    This statement declares and initializes a list of 3 characters. Once the list is created, you can add items to the list.

    List<char> grades = new List<char>(); // declaration & initialization
    grades.Add('A');
    grades.Add('B');
    grades.Add('C');
    
    Console.WriteLine(grades.Count); // Will return 3
    Console.WriteLine(grades[1]); // Returns value B
    
    //Code that retrieves the second value from the list
    grades[1];

    Run Demo

    List<string> Vegetables = new List<string> { "Carrot", "Cucumber", "Tomato", "Onion", "Green Pepper" };
    
    //Type inference with var keyword
    var planets = new List<string> { "Mercury", "Venus", "Earth" };
    
    List<int> integerValues = new List<int> (3) { 1, 2, 3 };
    
    //Code that creates a list that holds decimal values
    List<decimal> decimalValues = new List<decimal> { 13.2m, 20.74m, 8.34m };

    Run Demo

    List<int> integerValues = new List<int>(); //Declaration
    integerValues = new List<int>() { 1, 2, 3, 4, 5, 6 }; // Initialization
    
    List<int> moreIntegerValues = new List<int>() { 7, 8 }; //Declaration & Initialization
    
    //Get single value from list
    Console.WriteLine(integerValues[1]); //By Index and Prints 2
    
    //Remove(), RemoveAt(), RemoveRange()
    integerValues = new List<int>() { 1, 2, 3, 4, 5, 6 };
    
    integerValues.Remove(2); // By Value
    integerValues.RemoveAt(1); //By Index
    integerValues.RemoveRange(1, 2);
    
    integerValues.ForEach(o => Console.WriteLine(o));// print
    
    //Add()
    integerValues = new List<int>() { 1, 2, 3, 4, 5, 6 };
    
    integerValues.Add(7);
    integerValues.Add(8);
    
    integerValues.ForEach(o => Console.WriteLine(o));// print
    
    //AddRange()
    integerValues = new List<int>() { 1, 2, 3, 4, 5, 6 };
    
    integerValues.AddRange(moreIntegerValues);
    
    integerValues.ForEach(o => Console.WriteLine(o)); // print
    
    //Insert(), InsertRange()
    integerValues = new List<int>() { 1, 2, 3, 4, 5, 6 };
    
    integerValues.Insert(2, 13);
    integerValues.InsertRange(2, moreIntegerValues);
    
    integerValues.ForEach(o => Console.WriteLine(o));// print
    
    //Contains(), Count, Count(), Capacity
    integerValues = new List<int>() { 1, 2, 3, 6, 5, 4 };
    
    Console.WriteLine(integerValues.Contains(2)); // Prints True
    Console.WriteLine(integerValues.Count); // Property prints 6
    Console.WriteLine(integerValues.Count()); // LINQ Method prints 6
    Console.WriteLine(integerValues.Capacity); // Property prints 8
                
    //Sort() 
    integerValues.Sort();
    
    integerValues.ForEach(o => Console.WriteLine(o));// print
    
    //Clear() 
    integerValues = new List<int>() { 1, 2, 3, 4, 5, 6 };
    
    integerValues.Clear();
    Console.WriteLine(integerValues.Count); // Prints 0
    
    //Loops
    integerValues = new List<int>() { 1, 2, 3, 4, 5, 6 };
    
    //ForEach loop
    integerValues.ForEach(o => Console.WriteLine(o));
    
    //foreach loop
    foreach (var value in integerValues)
        Console.WriteLine(value);
    
    //for loop
    for (var i = 0; i < integerValues.Count; i++)
    {
         Console.WriteLine(integerValues[i]);
    }

    Run Demo


    C# Reference | Microsoft Docs

    • List<T> Class
    • Object and Collection Initializers
    • IEnumerable<T> Interface
    • List<T>.ForEach(Action<T>) Method

    Понравилась статья? Поделить с друзьями:
  • Как написать letter of application
  • Как написать kpi для сотрудников
  • Как написать keylogger на python
  • Как написать k pop песню
  • Как написать json