List<T\> наследует следующие интерфейсы:
- IList<T\>
- ICollection\<T\>
- IEnumerable\<T\>
- IReadOnlyList\<T\>
- IReadOnlyCollection\<T\>
При удалении элемента по индексу, все последующие элементы в списке должны быть сдвинуты на одну позицию влево
### Insert
```csharp
public void Insert(int index, T item);
```
Используется для вставки элемента в список по указанному индексу. При этом все последующие элементы сдвигаются вправо.
Отличие Insert от индексатора в том, что Insert добавляет новый элемент и двигает остальные элементы, а индексатор изменяет значение указанного элемента.
Если вы попытаетесь вставить элемент на позицию, которая превышает длину списка, вы получите исключение ArgumentOutOfRangeException. Вот пример кода, который вызовет такое исключение:
```csharp
List<int> myList = new List<int> {1, 2, 3, 4, 5};
myList.Insert(10, 99); // Вызовет исключение ArgumentOutOfRangeException
```
Нужно быть осторожным с использованием метода `Insert` в `List<T>` при работе с большими объёмами данных. С точки зрения производительности (performance) это может быть довольно затратно, потому что в худшем случае метод `Insert` может привести к переносу всех элементов после вставляемого места.
Если вам нужно часто вставлять и удалять элементы, вам может быть полезно использовать другую структуру данных, например, `LinkedList<T>`, где вставка и удаление элементов происходит эффективнее, поскольку не требуется сдвигать другие элементы.
### Remove
Метод используется для удаления первого вхождения определенного объекта из списка.
```csharp
public bool Remove(T item)
```
Если элемент успешно найден и удален, метод возвращает `true`, в противном случае — `false`. Этот метод изменяет исходный список, уменьшая его размер на один, если элемент был найден и удален.
<u>Элементы смещаются!</u>
После удаления элемента все последующие элементы необходимо сдвинуть на одну позицию влево, чтобы заполнить образовавшуюся "дыру". Таким образом, сложность операции может быть оценена как O(n), где n — количество элементов в списке.
### RemoveAt
Удаляет элемент на определенной позиции в списке. Синтаксис выглядит следующим образом:
```csharp
public void RemoveAt(int index);
```
Если указанный индекс выходит за границы списка (то есть индекс меньше нуля или больше или равен количеству элементов в списке), то будет выброшено исключение ArgumentOutOfRangeException.
<u>Элементы смещаются!</u>
Удаление элемента из списка имеет сложность O(n), так как после удаления элемента все последующие элементы в списке должны быть сдвинуты на одну позицию влево. Это может быть неэффективно при частом удалении элементов из больших списков. Если вам нужно часто удалять элементы, рассмотрите возможность использования других структур данных, таких как LinkedList\<T\>, которые могут удалять элементы более эффективно.
### RemoveAll
Метод предназначен для удаления всех элементов из списка, которые удовлетворяют определенному условию, заданному в виде предиката.
```csharp
public int RemoveAll(System.Predicate<T> match)
```
Предикат — это делегат, который принимает элемент списка в качестве параметра и возвращает значение типа `bool`, указывающее, должен ли элемент быть удален (`true`) или нет (`false`).
Метод `RemoveAll` возвращает количество удаленных элементов.
Например, для удаления всех вхождений `2` можно использовать следующий код:
```csharp
numbers.RemoveAll(x => x == 2);
```
##### Производительность
При использовании метода `RemoveAll` минимизируется необходимость сдвига элементов.
Вместо того чтобы каждый раз, удаляя элемент, сдвигать оставшиеся элементы на одну позицию влево (как это происходит при использовании метода `Remove`), `RemoveAll` сначала определяет все элементы для удаления и затем выполняет сдвиг один раз, чтобы заполнить пробелы, оставшиеся после удаления всех этих элементов.
### IndexOf
```csharp
public int IndexOf(T item);
```
Возвращает индекс первого вхождения определенного элемента в `List<T>`. Этот метод начинает поиск с первого элемента и продолжает в направлении конца списка.
Если элемент найден в списке, метод возвращает индекс первого вхождения элемента. Если элемент не найден в списке, метод возвращает -1.
работает с асимптотической сложностью O(n), где n — это количество элементов в списке. Скорость работы этого метода зависит от количества элементов в списке, так как в худшем случае ему придется перебрать все элементы, чтобы найти нужный.
Он начинает искать с начала списка и проверяет каждый элемент, пока не найдет элемент, равный искомому, или не дойдет до конца списка.
### Индексатор
Индексатор используется для доступа или изменения существующих элементов в списке.
Он не может быть использован для добавления новых элементов. Если вы попытаетесь обратиться к элементу списка по индексу, который выходит за его размер, то вы получите исключение ArgumentOutOfRangeException.
### AddRange
Этот метод позволяет добавить диапазон элементов в коллекцию.
В случае `List<T>`, AddRange принимает `IEnumerable<T>` и добавляет все элементы из этого `IEnumerable<T>` в конец списка.
Вот пример использования метода AddRange:
```csharp
List<int> numbers = new List<int> { 1, 2, 3 };
IEnumerable<int> moreNumbers = new List<int> { 4, 5, 6 };
numbers.AddRange(moreNumbers);
// numbers теперь содержит { 1, 2, 3, 4, 5, 6 }
```
Как добавить словарь в список:
```csharp
List<int> keyList = new List<int>();
keyList.AddRange(dict.Keys);
List<string> valueList = new List<string>();
valueList.AddRange(dict.Values);
```
Обратите внимание, что метод AddRange добавляет элементы к существующим в списке, он не заменяет старые элементы новыми. Если вам нужно заменить все старые элементы новыми, вы можете сначала использовать метод Clear, а затем AddRange.
Метод AddRange обычно эффективнее, чем добавление элементов по одному в цикле с помощью метода Add, особенно для больших коллекций, поскольку AddRange может оптимизировать процесс добавления и минимизировать количество необходимых операций перераспределения памяти.
Метод AddRange доступен в нескольких классах коллекций в .NET Framework и .NET Core, включая `List<T>`, `HashSet<T>`, `SortedSet<T>` и `ConcurrentBag<T>`
**Когда я инициализирую список вот так, то могу ли я обратиться к элементу, не создавая элемент?**
```
inventoryC.Stacks = new List<Entity>(10);
inventoryC.Stack[6]
```
Когда вы инициализируете список с указанием размера, как вы это делаете `new List<Entity>(10)`, вы задаёте первоначальную вместимость списка. Это означает, что под список сразу выделится память под указанное количество элементов, что поможет оптимизировать работу списка при добавлении элементов.
Однако это не значит, что список сразу заполняется этим количеством элементов. В вашем случае, список все равно остается пустым после инициализации, и если вы попытаетесь обратиться к элементу по индексу, как inventoryC.Stack[6], вы получите исключение ArgumentOutOfRangeException, поскольку на данный момент в списке нет элементов.
Чтобы добавить элемент в список, вы должны использовать метод Add или Insert. Если вы хотите сразу заполнить список элементами, вы можете это сделать в момент инициализации, передав в конструктор список с нужными элементами.
### Equals
Сравнивает две коллекции по ссылке, а не по содержимому коллекций.
Это означает, что даже если две коллекции содержат одинаковые элементы, метод `Equals` вернет `false`, за исключением случая, когда обе переменные ссылаются на один и тот же объект в памяти.