obo.dev

Коллекции. Массивы (Array)

05 Dec 2022

Массивы (Array)

Массив - это еще один тип коллекций в программировании на Swift. Массив хранит различные значения одного типа в виде коллекции в упорядоченной форме. Порядок элемента задается благодаря положению в массиве через индекс. Индексы Можно использовать множества как альтернативу массиву, когда порядок элементов значения не имеет или когда необходимо быть уверенным в том, что значения внутри коллекции не повторяются.

Массив - это коллекция неуникальных упорядоченных однотипных данных.

Массив в Swift можно представить как поезд с вагонами, которые идут друг за другом с определенными порядком. Если поменять вагоны местами, то и их номера в порядке тоже поменяются. Например, поменять местами первый и последний вагон. Тогда первый вагон будет с порядковым номером последнего, а последний станет под порядковым номером 1.

Что из себя представляет массив?

В массиве можно хранить однотипные данные в определенном порядке и при этом элементы массива могут повторятся.

Пример:

let names = ["Arthur", "Ford", "Trillian", "Zaphod", "Marvin"]
print(names)

// Output
// ["Arthur", "Ford", "Trillian", "Zaphod", "Marvin"]

Нельзя изменить тип массива после того, как он был объявлен.

В квадратных скобках помещаются элементы массива. Элементы разделяются между собой запятыми. Индексы представляют собой элементы последовательности целых положительных чисел, начиная с нуля. Первый элемент массива имеет индекс “0”, второй элемент массива - индекс “1” и так далее.

Все элементы массива должны быть единого типа данных.

Если в качестве значений элементов необходимо указать данные разных типов, тогда тип данных для элементов в массиве будет по типу “Any”.

Создание массива

Если создать массив и присвоить его переменной, то созданная коллекция будет изменяемой. Это обозначает, что можно изменить коллекцию после ее создания путем добавления, удаления или изменения элементов этой коллекции. И наоборот, когда вы присвоите массив константе, то массив будет неизменяемым, а его размер и содержимое не может быть изменено.

Тип массива в Swift в полной форме пишется как Array<Element>, где Element - это тип данных элементов массива.

В сокращенной форме тип данных массива можно написать как [Element].

Хотя две формы функционально идентичны, краткая форма является предпочтительной и используется чаще.

Декларирование массива. В этом примере - элементы будут со строковым типом данных:

var array1: Array<String>

Или так:

var array2: [String]

После объявления массива для дальнейшей работы необходимо инициализировать массив:

array1 = ["Adam"]
array2 = ["Ben"]

Общая форма объявления и инициализации массива:

var array3: Array<String> = ["Adam", "Ben", "Chack"]
var array4: [String] = ["Dilan", "Ellon", "Finn"]

Еще одна форма объявления и инициализации массива (Создание массива с литералом массива):

var array5 = Array<String>(arrayLiteral: "Gin", "Henry", "Isaak")
var array6 = [String](arrayLiteral: "John", "Kim", "Lasly")

Таким способом создается новый экземпляр коллекции, который содержит элементы последовательности. В данном примере - последовательность строковых элементов.

В случае array5 требуется добавлять элементы того типа, который указан (Array). Если вместо *Array* указать *Array*, то тип данных массива будет определен исходя из типа элементов. Если элементы будут разного типа, то тогда тип данных массива будет *Any*.

Объявление и инициализация массива без указания типа данных (Создание массива с литералом массива):

var array7 = ["Mary", "Nansy", "Olaph"]

Тип коллекции будет определен исходя из типа данных элементов, с которыми коллекция инициализируется. Такая сокращенная форма используется чаще всего.

Еще один способ инициализации массива с помощью повторяющегося значения. Указывается элемент, с которым массив инициализируется и количество раз, сколько он повторяется в массиве:

let array8 = Array(repeating: "Z", count: 5)
print(array8)

// Output
// ["Z", "Z", "Z", "Z", "Z"]

Объявление пустого словаря с помощью пустого инициализатора:

let array9 = [String]()
print(array9)

// Output
// []

let array10 = Array<String>()
print(array10)

// Output
// []

Еще один способ объявления пустого словаря с помощью присвоение значения пустого массива:

let array11: [String] = []
print(array11)

// Output
// []

Просто присвоить пустой массив без указания типа - нельзя, так как будет ошибка: нельзя определить тип данных элементов массива.

Работа с массивом

Можно получить доступ к массиву и изменять его либо через его методы и свойства, либо используя синтаксис индексов.

Работа с элементами массива: добавление, получение, изменение и удаление элементов массива

Массивы — это коллекция элементов одного типа. Каждый элемент имеет числовой индекс, начиная с 0.

Для примера работы со массивом создаем массив “names”:

var names = ["Arthur", "Ford", "Trillian", "Zaphod", "Marvin"]
print(names)

// Output
// ["Arthur", "Ford", "Trillian", "Zaphod", "Marvin"]

Если выписать индексы и значения, получим:

0: Arthur
1: Ford
2: Trillian
3: Zaphod
4: Marvin

Добавление элемента массива

Для добавления нового элемента в конец массива:

names.append("Eddie")
print(names)

// Output
// ["Arthur", "Ford", "Trillian", "Zaphod", "Marvin", "Eddie"]

Используется метод append(Element), чтобы добавить новый элемент в конец массива. Добавляемый элемент должен иметь тот же тип, что и другие элементы в коллекции.

Сложность

O(1) в среднем по многим вызовам append(Element) в одном и том же массиве.

Также можно комбинировать массивы. Для этого можно использовать операторы + и += (операторы сложения и присваивания):

names += ["Heart of Gold"]
print(names)

// Output
// ["Arthur", "Ford", "Trillian", "Zaphod", "Marvin", "Eddie", "Heart of Gold"]

Вставка элементов в массив

Вставка элементов в массив аналогична удалению элементов. Для этого используется метод insert(_:, at:):

names.insert("Humma Kavula", at: 4)

Метод insert(Element, at: Int) вставляет в массив элемент по указанному индексу, Этот код вставит новое имя в индекс 4. Это означает, что элемент, который был в позиции 4, теперь сместится на одну позицию вправо.

Удаление элементов массива

Удаление элемента из массива по индексу - с индексом 2:

names.remove(at: 2)
print(names)

// Output
// ["Arthur", "Ford", "Zaphod", "Marvin", "Eddie", "Heart of Gold"]

Это удалит элемент Trillian из массива, потому что этот элемент имеет индекс 2.

Хотя Trillian является третьим элементом в массиве names, тем не менее, он имеет индекс 2, потому что массивы имеют нулевую индексацию. Каждый массив начинаются с индекса 0, поэтому любой n-й элемент имеет индекс n — 1.

Метод remove(at: Int) также возвращает удаленный элемент. То есть, можно его использовать:

var measurements: [Double] = [1.1, 1.5, 2.9, 1.2, 1.5, 1.3, 1.2]
let removed = measurements.remove(at: 2)
print(measurements)

// Output
// [1.1, 1.5, 1.2, 1.5, 1.3, 1.2]

print(removed)

// Output
// 2.9

Еще несколько полезных методов удаления элементов из массива:

  • removeFirst() - удаляет первый элемент из массива и возвращает его;
  • removeFirst(Int) - удаляет указанное количество элементов, начиная с начала;
  • removeLast() - удаляет последний элемент из массива и возвращает его;
  • removeLast(Int) - удаляет указанное количество элементов, начиная с конца;
  • removeSubrange(Range) - удаляет из массива элементы с индексами, которые соответствуют указанному диапазону;
  • popLast() - удаляет и возвращает последний элемент коллекции. Возвращаемое значение: последний элемент коллекции, если коллекция не пуста, в противном случае - nil.

Получение и изменение элементов массива

Можно получить значение элемента массива с помощью его индекса:

var names = ["Arthur", "Ford", "Trillian", "Zaphod", "Marvin"]
let user = names[2]
print(user)

// Output
// Trillian

Также можно использовать данный синтаксис для изменения массива:

names[2] = "Prostetnic Vogon Jeltz"
print(names)

// Output
// ["Arthur", "Ford", "Prostetnic Vogon Jeltz", "Zaphod", "Marvin"]

Можно менять часть элементов интервалами:

names[1...3] = ["Dart", "Yoda"]
print(names)

// Output
// ["Arthur", "Dart", "Yoda", "Marvin"]

этой командой мы удаляем 3 элементов (с первого по третий) и вместо них вставляем два новых, т.е. изменяться может так же и число элементов.

Работа с массивом

Можно узнать количество элементов в массиве через его read-only свойство count:

var names = ["Arthur", "Ford", "Trillian", "Zaphod", "Marvin"]
let countItem = names.count
print(countItem)

// Output
// 5

Логическое свойство isEmpty вернет true если массив пустой и вернет false - если массив не пустой.

Пример:

var names = ["Arthur", "Ford", "Trillian", "Zaphod", "Marvin"]
if names.isEmpty {
    print("Array is empty")
} else {
    print("Array is not empty")
}

// Output
// Array is not empty

Метод contains(_:) вернет true если в массиве есть указанный в методе элемент и вернет false - если в массиве нет такого элемента.

Свойство first — возвращает первый элемент массива (опциональный тип)

Свойство last — возвращает последний элемент массива (опциональный тип)

Метод randomElement() - возвращает случайный элемент массива (опциональный тип)

Сложность randomElement()

O(1), если коллекция соответствует RandomAccessCollection; в противном случае O(n), где n — длина коллекции.

Пример:

var names = ["Arthur", "Ford", "Trillian", "Zaphod", "Marvin"]
if let firstName = names.first {
    print(firstName)
}

// Output
// Arthur

if let lastName = names.last {
    print(lastName)
}


// Output
// Marvin 

Массивы можно объединять. В результате будет новый массив, в котором будут элементы первого и второго массива.

Внимание! Порядок сложения массивов важен.

Пример:

var numbers1 = [1, 2, 3]
var numbers2 = [7, 8, 9]
var numbers3 = numbers1 + numbers2
print(numbers3)

// Output
// [1, 2, 3, 7, 8, 9]

var numbers4 = numbers2 + numbers1
print(numbers4)

// Output
// [7, 8, 9, 1, 2, 3]

Если объединить массивы с разными типами данных, то результирующий массив будет с типом *Array*:

var numbrs5 = numbers1 + ["5"]
print(numbrs5, type(of: numbrs5))

// Output
// [1, 2, 3, "5"] Array<Any>

Итерация по массиву - Перебор значений массива с помощью цикла

Цикл for-in позволит последовательно перебрать все элементы массива:

let names = ["Arthur", "Ford", "Trillian", "Zaphod", "Marvin"]

for name in names {
    print(name)
}

// Output
// Arthur
// Ford
// Trillian
// Zaphod
// Marvin

Приведенный выше код выведет каждый элемент names. Внутри тела цикла for-in можно использовать локальную константу name в качестве текущего элемента. Каждый раз, когда цикл запускается, элемент из коллекции names назначается константе name и выполняется тело цикла. Это позволит выполнить некоторый код для каждого элемента в коллекции.

Также, можно перебрать массив по индексам. В этом случае следует учитывать, что индекс первого элемента будет ноль. Тогда индекс второго - 1, а последнего - на единицу меньше от количества элементов в массиве. Таким образом диапазон перебора по индексам можно записать таким образом:

  • 0…array.count - 1

Или

  • 0..<array.count

Подробнее о диапазонах - смотреть в отдельной статье.

Следует учитывать, что теперь в каждой итерации локальной константе в качестве значения будет присвоено значение из этого диапазона, что соответствует индексам массива. А это обозначает, что теперь для получения элемента массива следует обращаться к массиву по индексу.

Пример:

let names = ["Arthur", "Ford", "Trillian", "Zaphod", "Marvin"]

for index in 0...names.count - 1 {
    print(names[index])
}

// Output
// Arthur
// Ford
// Trillian
// Zaphod
// Marvin

Метод enumerated() позволяет получить последовательность пар из индекса и значения элементов массива:

let names = ["Arthur", "Ford", "Trillian", "Zaphod", "Marvin"]

for (index, value) in names.enumerated() {
    print("\(index) - \(value)")
	if (value == "Ford") {
		print(index)
	}
}

// Output
// 0 - Arthur
// 1 - Ford
// 1
// 2 - Trillian
// 3 - Zaphod
// 4 - Marvin

Еще несколько полезных свойств и методов

Метод index(of:) - возвращает первый индекс, в котором указанное значение появляется в коллекции. Возвращаемое значение опционального типа, так как такого элемента может не оказаться в коллекции.

Метод min() - возвращает минимальный элемент в последовательности. Возвращаемое значение опционального типа, так как такого элемента может не оказаться в коллекции.

Метод max() - возвращает максимальный элемент в последовательности. Возвращаемое значение опционального типа, так как такого элемента может не оказаться в коллекции.

Метод dropFirst(_:Int) - возвращает подпоследовательность, содержащую все, кроме заданного количества начальных элементов. В аргументах указывается количество элементов, которые необходимо удалить с начала коллекции. Это значение должно быть больше или равно нулю. Если количество отбрасываемых элементов превышает количество элементов в коллекции, результатом является пустая подпоследовательность.

let numbers = [1, 2, 3, 4, 5]
print(numbers.dropFirst(2))

// Output
// [3, 4, 5]

print(numbers.dropFirst(10))

// Output
// []

Метод dropLast(_:Int) - возвращает подпоследовательность, содержащую все, кроме заданного количества конечных элементов. В аргументах указывается количество элементов, которые необходимо удалить с конца коллекции. Это значение должно быть больше или равно нулю. Если количество отбрасываемых элементов превышает количество элементов в коллекции, результатом является пустая подпоследовательность.

let numbers = [1, 2, 3, 4, 5]
print(numbers.dropLast(2))

// Output
// [1, 2, 3]

print(numbers.dropLast(10))

// Output
// []

Метод reverse() - меняет местами элементы в массиве в обратном порядке. В итоге исходный массив меняется.

var number = [1, 2, 3, 4]
number.reverse()
print(number)

// Output
// [4, 3, 2, 1]

Метод reversed() - возвращает массив с элементами исходной коллекции в обратном порядке. В итоге исходный массив не меняется, так как создается новая коллекция.

var number = [1, 2, 3, 4]
var numberReversed = number.reversed()
print(number)

// Output
// [1, 2, 3, 4]

print(numberReversed)

// Output
// [4, 3, 2, 1]

Метод joined(separator: String) - возвращает новую строку, объединяя элементы последовательности, добавляя заданный разделитель между каждым элементом. separator - строка для вставки между каждым из элементов в этой последовательности. Разделителем по умолчанию является пустая строка.

let cast = ["Vivien", "Marlon", "Kim", "Karl"]
let list = cast.joined(separator: ", ")
print(list)

// Output
// Vivien, Marlon, Kim, Karl

Метод swapAt(Self.Index, Self.Index) - меняет местами два элемента в массиве согласно указаных в методе индексов.

Примечание: swapAt() вызовет фатальную ошибку, если попытаться выполнить обмен за пределы длины массива.

var numbers = [1, 2, 3, 4, 5]
print(numbers)

// Output
// [1, 2, 3, 4, 5]

numbers.swapAt(0, 1)
print(numbers)

// Output
// [2, 1, 3, 4, 5]

Еще полезные ссылки

Также информацию по массивам можно получить на странице официальной документации (Узнать больше про методы и свойства массивов).

Ссылки на официальную документацию: