Всем доброго времени суток. Сегодня мы с вами познакомимся с такой абстракцией, как структура данных на примере списков, массивов и строк. В программировании достаточно часто возникают ситуации, когда требуется работать не с одним, а с несколькими значениями сразу. Причем, в зависимости от той задачи, что вы решаете, работать со значениями вы будете совершенно по разному. Структура данных как раз и является способом объединения нескольких значений вместе, по каким либо правилам, для того, чтобы с ними было проще работать в дальнейшем. Одно из самых простых и в то же время полезных структур данных является список. Набор из скольких-то элементов определенного типа, собранных вместе. Что это значит? Во-первых, список может содержать любое количество элементов, от нуля до бесконечности. Если вас внезапно нет значений, с которыми мы могли бы работать, пустой список как раз и соответствует такому случаю. Во-вторых, у списка есть размер. То количество элементов, которые список в себя содержит. У пустого списка размер равен нулю, у списка с каким-то набором элементов он равен количеству этих самых элементов в списке, в третьих, все элементы списка должны иметь один и тот же тип. Это наверное самое серьезное ограничение, которые данная структура данных предъявляет вам. Если вы хотите одновременно работать с числом и со строкой, например, то список вам в этом не поможет. Для подобных случаев есть другие абстракции, которые мы с вами обсудим в следующих уроках. В четвертых, элементы в списке расположены в определенном порядке, и этот порядок является существенным для некоторых операций, которые можно со списками делать. Все это позволяет использовать списки как для порядочных данных, все запланированные вами дела на сегодня в порядке уменьшения важности, например, так и для неупорядоченых данных, и для которых вы можете просто не учитывать порядок этих самых элементов в списке. Что все это значит на практике? Вспомним, что несколько раньше мы с вами пробовали написать функцию, которая находит корень биквадратного уравнения. Вместе с тем все мы знаем, что биквадратное уравнение может иметь от нуля до четырех корней, которые как раз и можно представить как список. Вот как выглядит наша функция решения биквадратного уравнения с поддержкой списков. В случае, если наше уравнение не имеет решений, мы возвращаем, вспоминая то, о чем говорили раньше, пустой список, если же решение есть, мы их считаем и собираем вместе в итоговый список, который возвращаем из функции. Что интересного можно заметить в нашем решении. Во-первых, что списки имеют, на первый взгляд, не совсем понятный тип List<Double>. Если с самим списком все понятно, List и есть список, то что такое <Double> в треугольник скобках? Для ответа на этот вопрос, можно вспомнить, что список, это набор элементов одного и того же типа, и наверное было бы неплохо этот тип указать. Для этого и служат типовые аргументы, аргументы указываемые после так называемого параметризованного типа в треугольник скобках. В данном случае мы работаем со списком действительных чисел, который как раз и задаётся как List<Double>. Во-вторых, для создания списков мы используем функцию listOf. Аргументами этой функции являются те элементы, которые мы хотим собрать в один список. Если их нет, мы получим пустой список, если они есть, то мы получим список, которые содержит ровно заданные нами элементы. У многих из вас может возникнуть вопрос: а как функция листов понимает какой типовой аргумент должен быть у возвращаемого списка? Здесь нам в очередной раз помогает такая особенность Котлина, как вывод типов. Если компилятор может понять какой тип должен быть у элемента списка из контекста его использования, его можно не указывать явно, компилятор сделает это за вас. В-третьих, списки можно складывать, что мы, например, делаем когда собираем вместе два набора корней уравнения для наших двух дискриминантов. Операция сложения делает именно то, что и должна делать подобная операция исходя из здравого смысла. Делает из двух отдельных списков один общий, который содержит все элементы как из первого, так и из второго списка, с сохранением их порядка. Понятно, что это далеко не единственная операция, которая доступна над списками. Основные из них мы рассмотрим с вами чуть позже. Самые пытливые слушатели еще в самом начале заметили, что наша функция решения биквадратного уравнения 4 раза делает одно и то же, решает уравнение x в квадрате равно y. В случае, когда вам в программе необходимо сделать какое-то сложное действие несколько раз, его обычно выносят в отдельную функцию. В нашем случае, это вспомогательная функция решения квадратного уравнения выглядит следующим образом. Обратите внимание, что в подобном случае использования оператора if, итоговым результатом какой либо ветки является последний оператор внутри нее. В качестве альтернативного способа, эту функцию можно попробовать реализовать при помощи оператора when, например вот так. С использованием нашей новой вспомогательной функции, мы можем переписать функцию поиска корней биквадратного уравнения так, как представлена на слайде. Если сравнить ее с предыдущей версией, то мы сократили функцию вдвое и при этом сделали ее еще и более читаемой. Как мне кажется, это вполне себе успех. Давайте теперь попробуем протестировать наше решение на нескольких биквадратных уравнениях. Вот наши примеры и как они выглядят в виде тестов. Обратите внимание, что здесь, в отличие от примеров выше, нам приходится явно указывать типовые аргументы в функции листов, когда оно вызывается без аргументов. В данном контексте компилятор Котлина не может понять, какой тип должен быть у элементов списка, поэтому мы должны ему явно подсказать, что нас интересуют списки действительных чисел. Запустим наши тесты, и что мы с вами видим? Последний тест не прошел, потому что элементы в списках оказались в разном порядке. Как мы с вами обсуждали раньше, список- это упорядоченная последовательность элементов, поэтому два набора элементов с разным порядком порождают два разных, с точки зрения Котлина, списка. Чтобы исправить наш тест, можно, например, сортировать списки перед тем как их сравнивать. Делается это при помощи функции sorted, который является функцией с получателем. В качестве своего результата она возвращает новый список, который содержит все элементы списка получателя, того списка, над которым мы sorted и вызвали, в отсортированном порядке. Если попробовать запустить наши тесты теперь, то все они должны успешно завершиться. Мы, ребята, умеем решать биквадратные уравнения, и это очень и очень здорово. Давайте посмотрим, какие еще операции, кроме сложения и сортировки, можно делать со списками. К списку можно прибавить не только другой список, но и отдельный элемент. Итоговый список будет содержать все элементы исходного списка с добавленным в конец, новым. Из списка можно достать элемент находящийся на определенной позиции при помощи операции индексирования, при этом нумерация элементов начинается с нуля, а не с единицы. Понятно, что для номеров или индексов от нуля до размера списка без одного, почему именно из одного, видно на примере, мы можем вернуть соответствующий элемент списка. А что мы можем сделать, если индекс внезапно выходит из размеры списка слева или справа. В принципе ничего нормального мы сделать не можем. Достать из воздуха то, чего нет, к сожалению невозможно, поэтому в таком случае, если индекс не соответствует списку, выполнение программы прерывается соответствующей ошибкой и выхода за границы списка. Если необходимо, мы можем сделать обратную операцию и попробовать найти в списке индекс какого-то интересующего нас элемента при помощи функции indexOf. В случае, если такого элемента в списке нет, ono vernet nam -1. Если элемент есть, то функция вернёт нам такой индекс, по которому списку и находится соответствующий элемент. Кроме этих, есть еще много других операций над списками, о которых вы можете почитать более подробно в референсе языка Котлин по следующему адресу. По собственному опыту могу сказать: знание того, что уже сделали за вас и до вас, половина, а то и больше успеха при программировании. Если у вас возникла необходимость в какой-то необычной операции, например, со списком, не поленитесь, сходите и посмотрите в реферанс. Вполне возможно, что эта операция уже реализована в стандартной библиотеке. В таком случае, вместо того, чтобы изобретать велосипед, вы можете просто воспользоваться уже готовой функцией. Тем самым вы облегчите жизнь как себя, так и вашим коллегам.