---
title: 3.1. Коллекции(массив, словарь). Обход по коллекциям на примере for-in
tags: Templates, Talk
description: View the slide with "Slide Mode".
---
# 3.1. Коллекции: массив, словарь. Обход по коллекциям на примере for-in
# План занятия
1. Массив и все что с ним связано
2. Что такое словарь?
3. Как перебрать массив и словарь с помощью for-in
---
## Вспоминаем прошлые занятия
- Для чего нужны преобразования типов данных?
- Какие условные конструкции вы знаете?
---
## Введение
В определенный момент при разработке сталкиваешься с моментом когда у тебя много переменных отвечающих за одно и тоже и плодить их дальше нет никакого смысла, тут нам на помощь приходят коллекции.
Давайте рассмотрим все возможные коллекции по порядку.
## Массивы
Массив это упорядоченный набор элеменов одного типа данных. Общение с элементами массива происходит по индексу (порядковому номеру элемента массива).
Индексы это числа с типом данных Int. Элементы массива индексируются с 0. Массив является простой переменной или константой, которая хранит несколько объектов одного типа данных.
### Объявление массива
Рассмотрим какими способами возможно объявить массив:
```javascript=
// Полная форма
var имяМассива: Array<Тип>
// Краткая форма
var имяМассива: [Тип]
```
Например:
```javascript=
var numbers: [Int]
```
В данном примере объявлен массив numbers с объектами типа Int.
Чтобы начать работать с массивом необходимо его проициализировать. то есть присвоить элементам массива данным того типа которого мы объявили. Например:
```javascript=
var numbers: [Int] = [1, 2, 3, 4, 5]
var numbers2: Array<Int> = [1, 2, 3, 4, 5]
print(numbers)
```
В данном примере ты объявили и проинициализировали два массива разными способами указав типы данных используемые в массиве. Мы так же можем не указывать тип при присвоении, Тогда компилятор сам после инициализации присвоит тип данных для переменной/константе. Например:
```javascript=
var numbers = [1, 2, 3, 4, 5]
```
На языкеSwift есть возможность объявлять пустые массивы:
```javascript=
var numbers = [Int]()
// или так
var numbers2 : [Int] = []
print("В массиве numbers \(numbers.count) элементов")
// В массиве numbers 0 элементов
```
При объявлении пустых массивов количество элементов будет рано 0. У массивов есть свойство count которое определяет количество элементов в массиве.
### Доступ к элементам массива
Как мы узнали выше то у каждого элемента массива есть свой индекс, благодаря которому мы можем обратится к значению этого элемента или изменить его. Например:
```javascript=
var numbers = [11, 12, 13, 14, 15, 16]
print(numbers[0]) // 11
numbers[0] = 21
print(numbers[0]) // 21
```
Чтобы обратится к элементу массива указывают в квадратных скобках номер элемента в массиве. Например: numbers[0]
В примере выше массив содержит 6 элементов Как мы с вами уже знаем индексы начинаются с 0, следовательно последний элемент массива из примера будет 5. Если обратится к элементу с индексом превышающем 5 произойдет ошибка. Например:
```javascript=
print(numbers[6]) // ошибка
```
При изменении сразу нескольких элементом массива можно использовать последовательности для определения индексов для замены:
```javascript=
var numbers = [5, 6, 7, 8, 3]
numbers[1...3] = [105, 106, 103]
print(numbers) // 5, 105, 106, 103, 3
```
В примере выше последовательность 1...3 говорит нам что мы будем работать с элементами индексы которых находятся в интервале от 1 до 3. И мы присваиваем им новые значения.
### Размер массива
Свойство count получает количество элементов массива:
```javascript=
var numbers: [Int] = [1, 2, 3, 4, 5, 6, 7, 8]
print("В массиве numbers \(numbers.count) элементов") // В массиве numbers 8 элементов
```
Однако есть еще 1 способ проверить пустой массив или нет. Свойство isEmpty проверяет массив на пустоту и возвращает true если массив пуст:
```javascript=
var numbers: [Int] = [1, 4, 8]
if numbers.isEmpty {
print("массив пуст")
} else {
print("в массиве есть элементы")
}
```
### Перебор массива
Массив можно перебрать по элементам циклом for:
```javascript=
var numbers: [Int] = [1, 2, 3, 4, 5, 6, 7, 8]
for i in numbers {
print(i) // 1, 2, 3, 4, 5, 6, 7, 8,
}
```
Так же есть вариант перебора циклом for через индексы:
```javascript=
var numbers: [Int] = [1, 2, 3, 4, 5, 6, 7, 8]
for i in 0 ..< numbers.count {
print(numbers[i]) // 1, 2, 3, 4, 5, 6, 7, 8,
}
```
У массива есть метод forEach() с помощью которого можно перебрать элементы массива. Параметром данного метода является функция которая будет производить действия над элементом массива:
```javascript=
var numbers: [Int] = [1, 2, 3, 4, 5, 6, 7, 8]
numbers.forEach({print($0)})
```
В примере выше это функция печати элемента в консоль.
Метод enumerated() получает не только элемент массива, но и его индекс:
```javascript=
var names: [String] = ["Tom", "Alice", "Kate"]
names.enumerated().forEach({print("\($0) - \($1)")})
for (index, value) in names.enumerated() {
print("\(index) - \(value)")
}
```
### Создание массива из последовательности
Давайте рассмотрим все возможные способы создания массивов с помощью последовательностей:
```javascript=
var numbers = Array (1...5) // [1, 2, 3, 4, 5]
var numbers2 = [Int] (3..<7) // [3, 4, 5, 6]
print(numbers) // [1, 2, 3, 4, 5]
print(numbers2) // [3, 4, 5, 6]
```
```javascript=
var numbers = [Int] (repeating: 5, count: 3)
// или так
var numbers2 = Array (repeating: 5, count: 3)
// эквивалентно массиву var numbers: [Int] = [5, 5, 5]
print(numbers) // [5, 5, 5]
```
При создании массивов подобным образом из элементов ссылочных типов ( с которыми мы познакомимся позже ), стоит помнить что все элементы массива будут хранить в памяти одну и туже ссылку:
```javascript=
class Person{
var name: String
init(name: String){
self.name = name
}
}
let tom = Person(name: "Tom")
var people = Array (repeating: tom, count: 3)
people[0].name = "Bob"
for person in people{
print(person.name)
}
// Bob
// Bob
// Bob
```
### Сравнение массивов
Массивы равны в том случае если у них равно количество элементов и элементы стоящие на одинаковых позициях равны между собой:
```javascript=
var numbers: [Int] = [1, 2, 3, 4, 5]
let nums = [1, 2, 3, 4, 5]
if numbers == nums{
print("массивы равны")
}
else {
print("массивы не равны")
}
```
В примере выше показано равенство массивов.
### Копирование массива
При копировании массива создается копия идентичная основному массиву, с которой можно работать отдельно от основного:
```javascript=
var numbers: [Int] = [1, 2, 3, 4, 5]
var nums: [Int] = numbers
nums[0] = 78
print(numbers) // [1, 2, 3, 4, 5]
print(nums) // [78, 2, 3, 4, 5]
```
При копировании можно использовать последовательности чтобы указать элементы с какими индексами необходимо скопировать в новый массив:
```javascript=
var numbers: [Int] = [1, 2, 3, 4, 5]
var nums = numbers[1...3]
print(nums[1]) // 2
print(nums) // [2, 3, 4]
```
В примере выше показано как копируются элементы с индексами от 1 до 3. При копировании сохраняются и индексы следовательно в данном примере индекс первого элемента нового массива будет 1, а не 0.
### Добавление в массив
У массива есть метод append() который добавляет новый элемент в массив:
```javascript=
var numbers = [8, 11, 13, 14]
numbers.append(20)
print(numbers) // 8, 11, 13, 14, 20
```
Так же есть метод insert() с помощью которого можно вставить элемент в конкретное место массива:
```javascript=
var numbers = [8, 11, 13, 14]
numbers.insert(10, at: 3) // вставка числа 10 на 3-й индекс
print(numbers) // 8, 11, 13, 10, 14
```
### Удаление из массива
Данные операции позволяют удалять элементы массива:
```
remove(at: index): удаляет элемент по определенному индексу
removeFirst(): удаляет первый элемент
removeLast(): удаляет последний элемент
dropFirst(): удаляет первый элемент
dropLast(): удаляет последний элемент
removeAll(): удаляет все элементы массива
```
```javascript=
var numbers = [8, 11, 13, 14]
numbers.remove(at: 2) // удаляем 3-й элемент
print(numbers) // 8, 11, 14
```
Методы removeFirst/removeLast и dropFirst/dropLast отличаются тем, что одни возвращают удаляемый элемент, а другие возвращают массив без удаленного элемента:
```javascript=
var numbers = [8, 11, 13, 14]
var n = numbers.removeFirst() // 8
var subNumbers = numbers.dropFirst()
print(subNumbers) // [13, 14]
```
Для удаления всех элементов массива используется метод removeAll():
```javascript=
var numbers = [8, 11, 13, 14]
numbers.removeAll()
print(numbers) // []
```
### Сортировка массива
Метод sort используется для сортировки массива:
```javascript=
var numbers: [Int] = [10, 4, 12, 1, 3]
numbers.sort()
print(numbers) // [1, 3, 4, 10, 12]
```
В отличии от метода sort, метод sorted() создает новый отсортированный массив, не изменяя старый:
```javascript=
var numbers: [Int] = [10, 4, 12, 1, 3]
var nums = numbers.sorted()
print(nums) // [1, 3, 4, 10, 12]
```
Оба данных метода могут принимать параметр by для определения метода сортировки. Параметр by представляет собой функцию с двумя параметрами, которая проверяет истинность условия сортировки и ставит значение в нужном порядке в зависимости он результата функции.
```javascript=
var numbers: [Int] = [10, 4, 12, 1, 3]
numbers.sort(by: {$0 > $1})
print(numbers) // [12, 10, 4, 3, 1]
var nums = numbers.sorted(by: <)
print(nums) // [1, 3, 4, 10, 12]
```
В примере выше Выражение {$0 > $1} проверяет значение параметров для сортировки в обратном порядке (значение первого должно быть больше предыдущего). Так же данную сортировку можно записать еще проще в виде (by: >), результат от этого не изменится.
### Объединение массивов
Массивы с одинаковым типом данных можно объединять с помощью операции сложения:
```javascript=
var numbers1 = [5, 6, 7]
var numbers2 = [1, 2, 3]
var numbers3 = numbers1 + numbers2
print(numbers3) // 5, 6, 7, 1, 2, 3
```
### Фильтрация массивов
Метод filter() фильтрует в зависимости от функции которую принимает метод. Метод возвращает отфильтрованный массив.
```javascript=
var numbers: [Int] = [1, 2, 3, 4, 5, 6, 7, 8]
var filteredNums = numbers.filter({$0 % 2==0})
print(filteredNums) // [2, 4, 6, 8]
```
В примере выше метод filter проверяет условие деления элемента массива на 2 без остатка. Если условие выполняется то элемент попадает в отфильтрованный список.
Так же есть еще метод prefix() который проверяет условие до тех пор пока первый раз не вернет false. Условие задается параметром while которое возвращает значение Bool:
```javascript=
var numbers: [Int] = [1, 2, 3, 4, 5, 6, 7, 8]
var filteredNums = numbers.prefix(while: {$0 < 5})
print(filteredNums) // [1, 2, 3, 4]
```
В примере выше пока условие не вернет false все элементы до этого попадут в отфильтрованный массив,
Метод drop() - Работает совершенно наоборот он будет удалять элементы пока условие первый раз не вернет false:
```javascript=
var numbers: [Int] = [1, 2, 5, 3, 4, 5, 6, 7, 8]
var filteredNums = numbers.drop(while: {$0 < 5})
print(filteredNums) // [5, 3, 4, 5, 6, 7, 8]
```
### Преобразование массива
Чтобы преобразовать массив под необходимые нам параметры используется метод map(). После преобразования все Элементы образуют новый массив который возвращает данная функция:
```javascript=
var numbers: [Int] = [1, 2, 5, 3, 4, 5, 6, 7, 8]
var mapedNums = numbers.map({$0 * $0})
print(mapedNums) // [1, 4, 25, 9, 16, 25, 36, 49, 64]
```
В примере выше массив преобразовывается в массив квадратов элементов. Финальный массив это массив возведенных элементов в квадрад исходного массива.
### Многомерные массивы
Ранее мы пользовались только простыми массивами представляются в виде строки:
```javascript=
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
```
На языке Swift мы может использовать и сложные массивы, в которых элементы выступают в качестве массивов:
```javascript=
var table = [[1,2,3], [4,5,6], [7,8,9]]
// получаем вторую строку
var row2 = table[1] // [4,5,6]
// получаем первый элемент второй строки
var cell1 = row2[0] // 4
// получаем второй элемент первой строки
var cell2 = table[0][1] // 2
```
В примере выше в главном массиве содержаться еще 3 подмассива. Данный массив представляется нам в виде таблицы с тремя строками.
Для того чтобы обратится к строке нужно использовать первый индекс главного массива. Например: table[1]
Для того чтобы обратится к элементу в строке необходимо указать рядом еще и его элемент. Например: table[1][0].
Так же можно менять элементы в строке или строки целиком.
```javascript=
// изменим вторую строку
table[1] = [16, 25, 36]
// изменим второй элемент первой строки
table[0][1] = -12
```
Для перебора таких массивов используются вложенные циклы. Например:
```javascript=
// перебор по строкам
for row in table{
print(row)
}
// перебор таблицы по строкам и столбцам
for row in table{
for cell in row{
print(cell)
}
}
```
## Словари
Словарь это хранилище объектов обращение к которым построено по уникальному ключу. Доступ к объекту происходит по ключу словаря.
Объявление словаря происходит в формате [тип данных ключа : тип данных объекта]. Например:
```javascript=
var phones = ["Apple": "iPhone X", "Microsoft": "Lumia 1050", "Google": "Nexus X5"]
```
В примере выше объявлен словарь с 3-мя объектами. Рассмотрим первый элемент словаря: Ключ у нас имеет тип String и значение "Apple", а объект тип String а значение "iPhone X". Типы данных значения и ключа могут быть различными, главное условие что ключ должен быть всегда уникальным.
При инициализации мы можем явно указывать какие типы данных будут в словаре:
```javascript=
var phones: [String: String] = ["Apple": "iPhone X", "Microsoft": "Lumia 1050", "Google": "Nexus X5"]
```
Так же можем использовать полное определение типа:
```javascript=
var phones: Dictionary<String, String> = ["Apple": "iPhone X", "Microsoft": "Lumia 1050", "Google": "Nexus X5"]
```
Как и с массивами мы может создать пустой словарь:
```javascript=
var phones: Dictionary<String, String> = [:]
// альтернативный вариант
var phones2: [String: String] = [:]
// с использованием инициализатора
var phones3 = [String: String]()
```
Аналогично с массивом есть проверка на отсутсвие элементов в словаре isEmpty:
```javascript=
var phones: Dictionary<String, String> = [:]
if phones.isEmpty {
print("Словарь phones пуст")
} else {
print("В словаре phones есть элементы")
}
```
Свойтсво count - возвращает количество элементов в словаре:
```javascript=
var phones: [String: String] = ["Apple": "iPhone X", "Microsoft": "Lumia 1050", "Google": "Nexus X5"]
print(phones.count)
```
Зная ключ элемента можно обратится к элементу словаря или изменить его:
```javascript=
var phones: [String: String] = ["Apple": "iPhone X", "Microsoft": "Lumia 1050", "Google": "Nexus X5"]
// получение элемента по ключу
print(phones["Apple"]) // iPhone X
// изменение элемента
phones["Apple"] = "iPhone XS"
```
Так же для изменения элемента в словаре есть метод updateValue:
```javascript=
phones.updateValue("iPhone XS", forKey: "Apple")
print(phones["Apple"]) // iPhone XS
```
Чтобы удалить элемент из словаря необходимо присвоить ему значение nil:
```javascript=
phones["Google"] = nil
```
Так же можно сделать удаление элемента по ключу с помощью метода removeValue(), указав имя ключа в параметре forKey:
```javascript=
phones.removeValue(forKey: "Google")
```
Данный метод вернет значение удаляемого элемента, если такого элемента не будет вернется значение nil:
```javascript=
if let removedValue = phones.removeValue(forKey: "Google") {
print("Удален объект \(removedValue).")
} else {
print("Словарь не содержит удаляемого элемента")
}
```
### Перебор словаря
Чтобы перебрать все ключи и значения словаря используется цикл for-in аналогично перебору массива:
```javascript=
var phones: [String: String] = ["Apple": "iPhone X", "Microsoft": "Lumia 1050", "Google": "Nexus X5"]
for (manufacturer, model) in phones {
print("\(manufacturer): \(model)")
}
```
При данном переборе на каждой итерации цикла мы получаем кортеж типа (ключ, значение).
Так же можно отдельно перебирать ключи и отдельно значения.
Можно отдельно перебирать ключи и значения.
Как перебрать только ключи:
```javascript=
for manufacturer in phones.keys {
print(manufacturer)
}
```
Перебор значений:
```javascript=
for model in phones.values {
print(model)
}
```
### Создание словаря из массивов
На языке Swift есть возможность создать словарь из двух массивов с помощью функции zip(), которая создаст объект Zip2Sequence, а после этого передать этот объект в инициализатор словаря. Например:
```javascript=
let countries = ["Iran", "Iraq", "Syria", "Lebanon"]
let capitals = ["Tehran", "Bagdad", "Damascus", "Beirut"]
var seq = zip(countries, capitals)
var dict = Dictionary(uniqueKeysWithValues:seq)
for (key, value) in dict {
print("\(key) - \(value)")
}
```
В примере выше каждому элементу массива countries сопоставляется элемент массива capitals. После результат функции zip() передается в инициализатор словаря с помощью параметра uniqueKeysWithValues. После инициализации получаем словарь:
```
Iran - Tehran
Iraq - Bagdad
Syria - Damascus
Lebanon - Beirut
```
Нужно обязательно помнить что ключ это уникальное значение и данным методом нельзя использовать повторяющие элементы в массивах, но если есть повторяющиеся элементы необходимо использовать другой инициализатор словаря:
```javascript=
let countries = ["Iran", "Iraq", "Syria", "Lebanon", "Iran"]
let capitals = ["Tehran", "Bagdad", "Damascus", "Beirut", "Tehran"]
var seq = zip(countries, capitals)
var dict = Dictionary(seq, uniquingKeysWith:{return $1})
for (key, value) in dict {
print("\(key) - \(value)")
}
```
В примере выше мы объединяем два массива и передаем данную последовательность в инициализатор словаря, а так же второй параметр uniquingKeysWith который выступает в роли функции которая обрабатывает элементы повторяющихся ключей. В данном примере это два элемента, мы просто возвращаем второй элемент.
## Домашнее задание:
В массиве, содержащем положительные и отрицательные целые числа, вычислить сумму четных положительных элементов.
Массив придумайте сами.
Создайте словарь, который будет содержать информацию о ваших студентах и об их успехах. Ключом словаря должна быть фамилия, а значением — другой словарь, содержащий дату занятия и полученную на этом занятии оценку.
Тип данных словаря должен быть [String:[String:UInt]].
В вашем электронном журнале должно находиться по две оценки для каждого из трех учеников. Фамилии, даты занятий и оценки придумайте сами.