Главная страница
Навигация по странице:

  • Операции итерирования foreach, grouped, sliding

  • Преобразования toIndexedSeq, toIterable, toList, toMap, toSeq, toSet и toVector

  • Операция копирования copyToArray.

  • Операции извлечения элементов head, last, headOption, lastOption и find

  • Операции извлечения подколлекций

  • Операции тестирования элементов exists, forall и count

  • Операции специализированных сверток sum, product, min и max

  • Операция представления view

  • Что делает Абстрактный метод xs.iteratorИтератор, который возвращает каждый элемент в xsИтерирование

  • Отображения xs.map(f)Коллекция, получающаяся в результате примене­ния функции f к каждому элементу в xs 24 .3 . Трейт Iterable 519 Что

  • Получение информации о размере

  • Scala. Профессиональное программирование 2022. Одерски Мартин, Спун Лекс, Веннерс Билл, Соммерс ФрэнкО41 Scala. Профессиональное программирование. 5е изд спб. Питер, 2022. 608 с. ил. Серия Библиотека программиста


    Скачать 6.24 Mb.
    НазваниеОдерски Мартин, Спун Лекс, Веннерс Билл, Соммерс ФрэнкО41 Scala. Профессиональное программирование. 5е изд спб. Питер, 2022. 608 с. ил. Серия Библиотека программиста
    Дата27.04.2023
    Размер6.24 Mb.
    Формат файлаpdf
    Имя файлаScala. Профессиональное программирование 2022.pdf
    ТипДокументы
    #1094967
    страница54 из 64
    1   ...   50   51   52   53   54   55   56   57   ...   64
    24
    Углубленное изучение коллекций
    В Scala включена весьма элегантная и эффективная библиотека коллекций.
    На первый взгляд API коллекций представляется незаметным, однако вы­
    званные им изменения в вашем стиле программирования могут быть весьма существенными. Зачастую это похоже на работу на высоком уровне с основ­
    ными строительными блоками программы, представляющими собой скорее коллекции, чем их элементы. Этот новый стиль программирования требует некоторой адаптации. К счастью, ее облегчает ряд привлекательных свойств коллекций Scala. Они просты в использовании, лаконичны в описании, без­
    опасны, быстры в работе и универсальны.
    z z
    Простота использования. Небольшого словаря, содержащего от 20 до 50 методов, вполне достаточно для решения основного набора задач всего за пару операций. Не нужно морочить голову сложными ци­
    кличными структурами или рекурсиями. Стабильные коллекции и опе­
    рации без побочных эффектов означают, что вам не следует опасаться случайного повреждения существующих коллекций новыми данными.
    Взаимовлияние итераторов и обновления коллекций исключено.
    z z
    Лаконичность. То, что раньше занимало от одного до нескольких циклов, теперь можно выразить всего одним словом. Можно выпол­
    нять функциональные операции, задействуя упрощенный синтаксис, и без особых усилий комбинировать операции таким образом, чтобы в результате получалось нечто похожее на обычные алгебраические формулы.
    z z
    Безопасность. Чтобы разобраться в этом вопросе, нужен определенный опыт. Природа коллекций Scala с их статической типизацией и функци­
    ональностью означает, что подавляющее большинство потенциальных

    512 Глава 24 • Углубленное изучение коллекций ошибок отлавливается еще во время компиляции. Это достигается благо­
    даря следующему: y
    сами операции над коллекциями используются довольно широко, а следовательно, прошли проверку временем; y
    использование операций над коллекциями делает ввод и вывод явным в виде параметров функций и результатов;
    y эти явные входные и выходные данные являются предметом для ста­
    тической проверки типов.
    Суть заключается в том, что большинство случаев неверного использо­
    вания кода проявится в виде ошибок типа. И вовсе не редкость, когда программы, состоящие из нескольких сотен строк кода, запускаются с первой же попытки.
    z z
    Скорость. Операции с коллекциями, имеющиеся в библиотеках, уже настроены и оптимизированы. В результате этого использование кол­
    лекций обычно отличается высокой эффективностью. Тщательно на­
    строенные структуры данных и операции могут улучшить ситуацию, но в то же время, принимая решения, далекие от оптимальных, можно ее значительно ухудшить. Более того, коллекции были адаптированы под параллельную обработку на многоядерных системах. Параллельно обрабатываемые коллекции поддерживают те же самые операции, что и последовательно обрабатываемые, поэтому изучать новые операции и переписывать код не нужно. Последовательно обрабатываемые кол­
    лекции можно превратить в параллельно обрабатываемые, просто вы­
    звав метод par z
    z
    Универсальность. Коллекции реализуют одни и те же операции над любым типом там, где в этих операциях есть определенный смысл. Сле­
    довательно, используя сравнительно небольшой словарь операций, вы приобретаете множество возможностей. Например, концептуально строка является последовательностью символов. Следовательно, в коллекциях
    Scala строки поддерживают все операции с последовательностями. То же самое справедливо и для массивов.
    В этой главе мы даем углубленное описание API имеющихся в Scala классов коллекций с точки зрения их использования. Краткий тур по библиотекам коллекций мы совершили в главе 15. В этой главе нам предстоит поуча­
    ствовать в более подробном путешествии, в ходе которого мы покажем все классы коллекций и все определенные в них методы, то есть представим все сведения, необходимые для использования коллекций Scala.

    24 .1 . Изменяемые и неизменяемые коллекции 513
    24 .1 . Изменяемые и неизменяемые коллекции
    Как вам уже известно, в целом коллекции в Scala подразделяются на изме­
    няемые и неизменяемые. Изменяемые могут обновляться или расширяться на месте. Это значит, вы можете изменять, добавлять или удалять элементы коллекции как побочный эффект. Неизменяемые коллекции, напротив, всегда сохраняют неизменный вид. Но все же есть операции, имитирующие добавление, удаление или обновление, но каждая из таких операций воз­
    вращает новую коллекцию, оставляя старую без изменений.
    Все классы коллекций находятся в пакете scala.collection или в одном из его подпакетов: mutable
    , immutable и generic
    . Большинство классов кол­
    лекций, востребованных в клиентском коде, существуют в трех вариантах, которые имеют разные характеристики в смысле возможности изменения.
    Эти три варианта находятся в пакетах scala.collection
    , scala.collecti- on.immutable и scala.collection.mutable
    Коллекция в пакете scala.collection.immutable гарантированно неизменя­
    емая для всех. Такая коллекция после создания всегда остается неизменной.
    Поэтому можно полагаться на то, что многократные обращения к одному и тому же значению коллекции в разные моменты времени всегда будут давать коллекцию с теми же элементами.
    Коллекция в пакете scala.collection.mutable известна тем, что имеет ряд операций, изменяющих коллекцию на месте. Эти операции позволяют вам создавать код для самостоятельного изменения коллекции. Но при этом нужно четко понимать, что существует вероятность обновления из других частей исходного кода, и защищаться от нее.
    Коллекции в пакете scala.collection могут быть как изменяемыми, так и неизменяемыми. Например, scala.collection.IndexedSeq[T]
    является супертрейтом как для scala.collection.immutable.IndexedSeq[T]
    , так и для его изменяемого брата scala.collection.mutable.IndexedSeq[T]
    . В целом корневые коллекции в пакете scala.collection поддерживают трансфор­
    мирующие операции, которые влияют на целую коллекцию, такие как map и filter
    . Неизменяемые коллекции в пакете scala.collection.immutable обычно дополняют операциями добавления и удаления отдельных значений, а изменяемые коллекции в пакете scala.collection.mutable дополняются некоторыми модифицирующими операциями с побочными эффектами.
    Между корневыми и неизменяемыми коллекциями есть еще одно различие: клиенты неизменяемых коллекций получают гарантии того, что никто не

    514 Глава 24 • Углубленное изучение коллекций сможет внести в коллекцию изменения, а клиенты корневых коллекций знают только то, что не могут изменить коллекцию самостоятельно. Даже если статический тип такой коллекции не предоставляет операций для ее изменения, все же существует вероятность того, что в процессе выполнения программы она получит тип изменяемой коллекции, предоставив другим клиентам возможность вносить в нее изменения.
    По умолчанию в Scala всегда выбираются неизменяемые коллекции. На­
    пример, если просто написать
    Set без какого­либо префикса или ничего не импортируя, то будет получено неизменяемое множество, а если написать
    Iterable
    — то неизменяемый объект с возможностью обхода его элементов, поскольку имеются привязки по умолчанию, импортируемые из пакета scala
    . Чтобы получить изменяемые версии по умолчанию, следует явно указать collection.mutable.Set или collection.mutable.Iterable
    Последний пакет в иерархии коллекций — collection.generic
    . В нем со­
    держатся строительные блоки для абстрагирования поверх конкретных кол­
    лекций. Впрочем, постоянные пользователи коллекций должны ссылаться на классы в пакете generic только в крайних случаях.
    24 .2 . Согласованность коллекций
    Наиболее важные классы коллекций показаны на рис. 24.1.
    Эти классы имеют много общего. Например, каждая разновидность кол­
    лекции может быть создана с использованием единообразного синтаксиса, заключающегося в записи названия класса коллекции, за которым стоят элементы данной коллекции:
    Iterable("x", "y", "z")
    Map("x" –> 24, "y" –> 25, "z" –> 26)
    Set(Color.Red, Color.Green, Color.Blue)
    SortedSet("hello", "world")
    Buffer(x, y, z)
    IndexedSeq(1.0, 2.0)
    LinearSeq(a, b, c)
    Тот же принцип применяется и к конкретным реализациям коллекций:
    List(1, 2, 3)
    HashMap("x" –> 24, "y" –> 25, "z" –> 26)
    Методы toString для всех коллекций выводят информацию, аналогичную показанной ранее, с именем типа, за которым следуют значения элементов

    24 .2 . Согласованность коллекций 515
    Iterable
    Seq
    IndexedSeq
    ArraySeq
    Vector
    ArrayDeque (mutable)
    Queue (mutable)
    Stack (mutable)
    Range
    NumericRange
    LinearSeq
    List
    LazyList
    Queue (immutable)
    Buffer
    ListBuffer
    ArrayBuffer
    Set
    SortedSet
    TreeSet
    HashSet (mutable)
    LinkedHashSet
    HashSet (immutable)
    BitSet
    EmptySet, Set1, Set2, Set3, Set4
    Map
    SortedMap
    TreeMap
    HashMap (mutable)
    LinkedHashMap (mutable)
    HashMap (immutable)
    VectorMap (immutable)
    EmptyMap, Map1, Map2, Map3, Map4
    Рис. 24.1. Иерархия коллекций коллекции, заключенные в круглые скобки. Все коллекции поддерживают
    API, предоставляемый
    Iterable
    , но все их методы возвращают собственный класс, а не корневой класс
    Iterable
    . Например, у метода map класса
    List тип возвращаемого значения
    List
    , у метода map класса
    Set тип возвращаемого значения
    Set
    . То есть статический возвращаемый тип этих методов абсо­
    лютно точен:
    List(1, 2, 3).map(_ + 1) // List(2, 3, 4): List[Int]
    Set(1, 2, 3).map(_ * 2) // Set(2, 4, 6): Set[Int]

    516 Глава 24 • Углубленное изучение коллекций
    Равенство для всех классов коллекций также организовано единообразно: более подробно этот вопрос рассматривается в разделе 24.12.
    Большинство классов, показанных на рис. 24.1, существуют в трех вари­
    антах: корневом, изменяемом и неизменяемом (
    root
    , mutable и immutable
    ).
    Единственное исключение — трейт
    Buffer
    , существующий только в виде изменяемой коллекции.
    Далее в главе все эти классы мы рассмотрим поочередно.
    24 .3 . Трейт Iterable
    На вершине иерархии коллекций находится трейт
    Iterable[A]
    , где
    A
    — тип элементов коллекции. Все методы в этом трейте определены в терминах абстрактного метода iterator
    , который возвращает элементы коллекции один за другим.
    def iterator: Iterator[A]
    Классам коллекций, реализующим
    Iterable
    , нужно определить только этот метод, а все остальные методы могут быть унаследованы из
    Iterable
    В
    Iterable также определяется много конкретных методов, перечисленных в табл. 24.1. Их можно разбить на следующие категории.
    z z
    Операции итерирования foreach, grouped, sliding перебирают все эле­
    менты коллекции в порядке, который определяет ее итератор. Мето­
    ды grouped и sliding возвращают итераторы, которые, в свою очередь, возвращают не отдельные элементы, а, скорее, подпоследовательности элементов исходной коллекции. Максимальный размер этих подпоследо­
    вательностей указывается в качестве аргумента для этих методов. Метод grouped делит полученные элементы на инкременты, а sliding формирует по ним скользящее окно. Разницу между ними должен наглядно проде­
    монстрировать следующий код:
    val xs = List(1, 2, 3, 4, 5)
    val git = xs.grouped(3) // an Iterator[List[Int]]
    git.next() // List(1, 2, 3)
    git.next() // List(4, 5)
    val sit = xs.sliding(3) // an Iterator[List[Int]]
    sit.next() // List(1, 2, 3)
    sit.next() // List(2, 3, 4)
    sit.next() // List(3, 4, 5)

    24 .3 . Трейт Iterable 517
    z z
    Сложение ++ (псевдоним: concat
    ) складывает две коллекции вместе или добавляет все элементы итератора в коллекцию.
    z z
    Операции отображения map, flatMap и collect создают новую коллекцию путем применения некой функции к элементам коллекции.
    z z
    Преобразования toIndexedSeq, toIterable, toList, toMap, toSeq, toSet
    и toVector превращают коллекцию
    Iterable в неизменяемую. Все эти преобразования возвращают объект­получатель, если он уже соответству­
    ет требуемому типу коллекции. Например, применение toList к списку выдаст сам список. Методы toArray и toBuffer возвращают новую изме­
    няемую коллекцию, даже если объект­получатель соответствует. Метод to можно использовать для преобразования в любую другую коллекцию.
    z z
    Операция копирования copyToArray. Как следует из названия, копирует элементы коллекции в массив.
    z z
    Операции с размером isEmpty, nonEmpty, size, knownSize, sizeCompare
    и sizeIs имеют отношение к размеру коллекции. Чтобы вычислить коли­
    чество элементов коллекции, в некоторых случаях может потребоваться совершить обход, например в случае
    List
    . В других случаях коллек­
    ция может содержать бесконечное количество элементов, например
    LazyList.from(0)
    . Методы knownSize
    , sizeCompare и sizeIs предостав­
    ляют информацию о количестве элементов , обходя как можно меньшее количество элементов.
    z z
    Операции извлечения элементов head, last, headOption, lastOption
    и find выбирают первый или последний элемент коллекции или же пер­
    вый элемент, соответствующий условию. Однако следует заметить, что не все коллекции имеют четко определенное значение первого и послед­
    него. Например,
    HashSet может хранить элементы в соответствии с их хеш­ключами, и порядок их следования от запуска к запуску может изме­
    няться. В таком случае для разных запусков программы первый элемент
    HashSet также может быть разным. Коллекция считается упорядоченной, если всегда выдает свои элементы в одном и том же порядке. Большин­
    ство коллекций упорядочены, однако некоторые, такие как
    HashSet
    , таковыми не являются, отказ от упорядочения позволяет им быть более эффективными. Упорядочение зачастую необходимо, чтобы получать вос­
    производимые тесты и способствовать отладке. Поэтому коллекции Scala предоставляют упорядоченные альтернативы для всех типов коллекций.
    Например, упорядоченная альтернатива для
    HashSet

    LinkedHashSet z
    z
    Операции извлечения подколлекций
    takeWhile
    , tail
    , init
    , slice
    , take
    , drop
    , filter
    , dropWhile
    , filterNot и withFilter возвращают подколлек­
    цию, определяемую диапазоном индексов или предикатом.

    518 Глава 24 • Углубленное изучение коллекций z
    z
    Операции подразделения groupBy, groupMap, groupMapReduce,
    splitAt, span, partition и partitionMap разбивают элементы переданной коллекции на несколько подколлекций.
    z z
    Операции тестирования элементов exists, forall и count тестируют эле­
    менты коллекции на соответствие заданному предикату.
    z z
    Операции свертки foldLeft, foldRight, reduceLeft, reduceRight применя­
    ют бинарные операции к следующим друг за другом элементам.
    z z
    Операции специализированных сверток sum, product, min и max рабо­
    тают с коллекциями конкретных типов (
    numeric или comparable
    ).
    z z
    Операции со строками mkString и addString предоставляют альтерна­
    тивные способы преобразования коллекции в строку.
    z z
    Операция представления view — это коллекция, которая вычисляется лениво. Больше о представлениях вы узнаете из раздела 24.13.
    Таблица 24.1. Операции в трейте Iterable
    Что
    Что делает
    Абстрактный метод
    xs.iterator
    Итератор, который возвращает каждый элемент в xs
    Итерирование:
    xs.foreach(f)
    Применяет функцию f
    к каждому элементу xs
    Вызов f
    нужен только для получения побочных эффектов; по сути, foreach отбрасывает любой результат функции f
    xs.grouped(size)
    Итератор, который возвращает «блоки» коллек­
    ции фиксированного размера xs.sliding(size)
    Итератор, который возвращает скользящее окно по элементам этой коллекции
    Сложение
    xs ++ ys
    (или xs.concat(ys)
    )
    Коллекция, состоящая из элементов xs и ys
    Элемент ys
    — это коллекция
    IterableOnce
    , то есть
    Iterable или
    Iterator
    Отображения
    xs.map(f)
    Коллекция, получающаяся в результате примене­
    ния функции f
    к каждому элементу в xs

    24 .3 . Трейт Iterable 519
    Что
    Что делает
    xs.flatMap(f)
    Коллекция, получающаяся в результате приме­
    нения функции f
    , результатом которой является коллекция, к каждому элементу в xs и объединя­
    ющая результаты xs.collect(f)
    Коллекция, получающаяся в результате примене­
    ния частично примененной функции f
    к каждому элементу в xs
    , для которого она определена, и объ­
    единяющая результаты
    Преобразования
    xs.toArray
    Превращает коллекцию в массив xs.toList
    Превращает коллекцию в список xs.toIterable
    Превращает коллекцию в итерируемую коллекцию xs.toSeq
    Превращает коллекцию в последовательность xs.toIndexedSeq
    Превращает коллекцию в проиндексированную последовательность xs.toSet
    Превращает коллекцию в множество xs.toMap
    Превращает коллекцию пар «ключ — значение» в отображение xs.to(SortedSet)
    Обобщенная операция преобразования, которая принимает в качестве параметра фабрику коллекций
    Копирование
    xs copyToArray(arr,
    s,
    len)
    Копирует максимум len элементов в массиве arr
    , начиная с индекса s
    . Последние два аргумента необязательны
    Получение информации о размере
    xs.isEmpty
    Проверяет, является ли коллекция пустой xs.nonEmpty
    Проверяет, содержит ли коллекция элементы xs.size
    Количество элементов в коллекции xs.knownSize
    Количество элементов, если его можно вычислить за постоянное время. В противном случае
    –1
    xs.sizeCompare(ys)
    Возвращает отрицательное значение, если коллек­
    ция xs короче ys
    , положительное, если длиннее, и
    0
    , если обе коллекции имеют одинаковый раз­
    мер. Работает даже для бесконечных коллекций

    520 Глава 24 • Углубленное изучение коллекций
    Что
    Что делает
    xs.sizeIs < 42,
    xs.sizeIs != 42
    , и т. д.
    Сравнивает размер коллекции с заданным значе­
    нием, перебирая как можно меньше элементов
    1   ...   50   51   52   53   54   55   56   57   ...   64


    написать администратору сайта