September 18, 2023

Анонс обучающего курса на платформе Stepik. Часть 2.

1. Немного теории

Для повышения эффективности обработки структурированных данных используют их объединение в коллекции. Коллекция предлагает готовый набор средств работы с данными различной, иногда достаточно сложной структуры. Коллекции Microsotf .NET поддерживают списки, стеки, очереди, множества, словари и т.д. При этом коллекции позволяют применять единый стандартизованный подход к данным различной структуры.

Среда .NET предоставляет несколько типов коллекций, но мы остановимся только на одном: обобщенных коллекциях, которые часто также называют дженéриками (англ. generic). Все элементы в обобщенной коллекции имеют единый тип T, который указывается в программе, что позволяет создавать компилятору быстрый и надежный код. Подстановка конкретного типа на место T, которую выполняет компилятор, называется инстанцированием. Так, для коллекции List<T> мы должны указывать известный компилятору тип, например, List<integer>.

Обобщенные коллекции предоставляют методы для создания данных, их редактирования, добавления новых элементов и удаления существующих, а также поиска. Ко всем коллекциям применимы методы для работы с последовательностями и технология LINQ, следовательно вы уже умеете работать с коллекциями.

2. Как, ничего не зная об ООП, построить свой список List<T>

Термин list (англ. список) в информатике обозначает структуру, в которой данные упорядочены некоторым образом и могут повторяться. В таком определении список является моделью конечной математической последовательности. От массива список отличается возможностью удалять и добавлять элементы в любом месте. Сразу же отметьте, что реализация коллекции List<T> наиболее эффективно выполняет добавление и удаление элементов в конце списка, наименее эффективно - внутри него. Коллекция реализована на базе обыкновенного динамического массива, для которого добавлены методы вставки и удаления элементов.

type
  TList = array of integer;

function Add(Self: TList; elem: integer): Tlist; extensionmethod;
// добавление элемента elem в конец списка
begin
  Result := Self + |elem|;
end;

function Remove(Self: TList; elem: integer):TList; extensionmethod;
// удаление первого найденного элемента со значением elem
begin
  var i := Self.FindIndex(t -> t = elem);
  if i > -1 then Result := Self[:i] + Self?[i + 1:]
  else Result := Self
end;

begin
  var a: Tlist := |5, -2, 1, 4, 0, 4, 2|;
  a.Println;                              // 5 -2 1 4 0 4 2 
  a := a.Add(7);
  a.Println;                              // 5 -2 1 4 0 4 2 7
  a := a.Remove(0);
  a.Print                                 // 5 -2 1 4 4 2 7
end.

Конечно, если вам известны методы Add и Remove для списка List<T>, вы помните, что они работают, как процедуры, т.е. изменяют значение переданного им экземпляра коллекции, а не возвращают ее новый экземпляр. Здесь так написать нельзя, поскольку параметр Self не может указываться с var за исключением случая, когда он является строкой string. Но если освоите ООП, сможете создавать свои классы и там делать все "по-настоящему".

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