В статье рассмотрим принципы работы со списком List: создание списка и обращение к данными; добавление, удаление, поиск и сортировка элементов. Список List<T> 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 Также существует специальный цикл для работы со списками foreach. List<int> list = new List<int>() { 3, 4, 2, 0 }; foreach(int item in list) Console.WriteLine(item); Перебор списка 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, рассмотрена базовая работа (инициализация, обращение к данными) и методы для работы со списком: Добавление. Поиск. Удаление. Сортировка. Работа с диапазонами. Материалы по теме 👨🎓️ Самоучитель по C#: абстрактные классы и члены классов 👨🎓️ Учебник по C#: работа с коллекциями Dictionary 🧊 Руководство по С# для начинающих: массивы и цикл foreach
List<T> — класс из пространства имен System.Collections.Generic, список однотипных объектов. В отличие от массива, предоставляет набор методов, облегчающих работу, таких как добавление новых элементов (это удобно, когда неизвестно заранее сколько будет элементов).
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, т. к. при передаче списка в конструктор нового списка создается именно новый список, т. е. в памяти выделяется место для нового объекта, но заполняется теми же значениями, которые были в переданном списке.
list2 = list
Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека шарписта» Интересно, перейти к каналу
List<int> list = new List<int> { 1, 2, 3 }; List<int> list2 = new List<int>(list) { 4 };
Если вывести все значения из списка list2, будут выведены значения от 1 до 4.
list2
Также рассмотрим более сложный пример с пользовательским классом.
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) элементов. Для повышения производительности, если известен конечный размер списка, можно изначально задать его размер, что избавит от дополнительных выделений памяти.
_defaultCapacity
List
Аналогично как в массиве, допустимо обращаться к элементам списка в квадратных скобках по индексу.
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.
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.
for
List<int> list = new List<int>() { 3, 4, 2, 0 }; for(int i = 0; i < list.Count; i++) Console.WriteLine(list[i]);
Перебор списка for
Также существует специальный цикл для работы со списками foreach.
foreach
List<int> list = new List<int>() { 3, 4, 2, 0 }; foreach(int item in list) Console.WriteLine(item);
Перебор списка 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)
int BinarySearch(T item)
bool Contains(T item)
bool Exists(Predicate<T> match)
match
T Find(Predicate<T> match)
List<T> FindAll(Predicate<T> match)
Find
int FindIndex(Predicate<T> match)
int FindLastIndex(Predicate<T> match)
FindIndex
List<T> GetRange(int index, int count)
int IndexOf(T item)
-1
int LastIndexOf(T item)
bool Remove(T item)
true
false
int RemoveAll(Predicate<T> match)
void RemoveAt(int index)
void RemoveRange(int index, int count)
index
count
System.ArgumentException
void Clear()
void Sort()
void Reverse()
List<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter)
void CopyTo(T[] array)
void ForEach(Action<T> action)
break
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, рассмотрена базовая работа (инициализация, обращение к данными) и методы для работы со списком:
Ваш адрес email не будет опубликован. Обязательные поля помечены *
Сохранить моё имя, email и адрес сайта в этом браузере для последующих моих комментариев.
Δ
Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.