sorted(by:)
, который сортирует массив значений известного типа, основываясь на выходном значении сортирующего замыкания, которое Вы предоставляете. Как только он завершает процесс сортировки, то метод sorted(by:)
возвращает новый массив того же типа и размера, что и старый, элементы которое отсортированы в корректном порядке. Оригинальный массив не изменяется методом sorted(by:)
.
let names = ["Саша", "Алекс", "Артемий", "Оля", "Маша"]
Пример использует метод sorted(by:)
для сортировки массива значений String
в обратном алфавитном порядке.
sorted(by:)
принимает замыкание, которое имеет два аргумента того же типа, что и тип, содержащийся в массиве, и возвращает значение Bool
, чтобы сказать, должно ли первое значение появится перед или после второго значения, когда значения будут отсортированы. Сортирующее замыкание должно вернуть true
, если первое значение должно появится после второго, и false
- в противном случае.
String
, так что сортирующее замыкание должно быть функцией типа (String, String) -> Bool
.
sorted(by:)
:
func backward(_ s1: String, _ s2: String) -> Bool {
return s1 > s2
}
var reversedNames = names.sorted(by: backward)
// reversedNames теперь равен ["Саша", "Оля", "Маша", "Артемий", "Алекс"]
Если первая строка (s1) больше второй строки (s2), то функция backward(_:_:)
вернёт значение true
, обозначающее, что s1 должна появиться перед s2 в отсортированном массиве. Для символов в строке "больше чем" означает "появляется позже в алфавите чем". Это означает, что буква "B" "больше чем" буква "A", а строка "Tom" больше нежели строка "Tim". Это даст нам обратную алфавитную сортировку, где "Barry" будет расположен перед "Alex" и так далее.
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
} )
// reversedNames теперь равен ["Саша", "Оля", "Маша", "Артемий", "Алекс"]
Пример демонстрирует версию функции backward(_:_:)
с помощью выражения-замыкания из примера ранее.
backward(_:_:)
. В обоих случаях оно записывается как (s1: String, s2: String) -> Bool
. Однако для инлайн-замыкания параметры и возвращаемое значение записываются внутри фигурных скобок, а не снаружи их.
in
. Это ключевое слово обозначает, что определение параметров и возвращаемого типа завершено, и начинается тело функции.
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )
// reversedNames теперь равен ["Саша", "Оля", "Маша", "Артемий", "Алекс"]
Это иллюстрирует, что в общем вызов метода sorted(by:)
остался тем же. Пара круглых скобок продолжает обхватывать весь аргумент для метода. Однако аргумент теперь является инлайн-замыканием.
sorted(by:)
всё так же продолжает вызываться на массиве строк, так что аргумент должен быть функцией типа (String, String) -> Bool
. Это означает, что нет необходимости явно указывать (String, String)
и Bool
в качестве части определения выражения-замыкания. Так как все типы могут быть выведены, то возвращающая стрелка (->) и круглые скобки вокруг имён параметров могут быть так же опущены.
reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )
// reversedNames теперь равен ["Саша", "Оля", "Маша", "Артемий", "Алекс"]
sorted(by:)
цель замыкания понятно из факта, что имеет место быть сортировка, и для читателя будет безопасным принять, что замыкание скорее всего будет работать со значениями String
, так как массив имеет такой тип.
return
из их определения, как в случае с этой версией предыдущего примера:
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
Здесь функциональный тип аргумента метода sorted(by:)
делает понятным, что из замыкания должно быть возвращено значение типа Bool
. Так как тело замыкания содержит единственное выражение (s1 > s2), которое возвращает значение типа Bool
, так что нет никакой неопределённости, а ключевое слово return
может быть опущено.
in
так же может быть опущенной так как выражение-замыкание состоит только из одного лишь тела:
reversedNames = names.sorted(by: { $0 > $1 } )
Здесь $0 и $1 ссылаются на первый и второй аргументы типа String
.
String
в Swift определяет специальную строковую реализацию оператор больше чем (>) в качестве метода, который имеет два параметра типа String
, а возвращает значение типа Bool
. Это полностью совпадает с типом метода, который нужен методу sorted(by:)
. На самом деле Вы просто можете передать оператор больше-чем, и Swift выведет, что Вы хотите использовать его специальную строковую имплементацию.
reversedNames = names.sorted(by: >)
func someFunctionThatTakesAClosure(closure: () -> Void) {
// здесь будет тело функции
}
// Вот так эта функция вызвается без trailing-замыкания:
someFunctionThatTakesAClosure(closure: {
// Здесь будет тело замыкания
})
// Вот так эта функция вызвается с помощью trailing-замыкания:
someFunctionThatTakesAClosure() {
// Здесь будет тело trailing-замыкания
}
sorted(by:)
в качестве trailing-замыкания.
let names = ["Саша", "Алекс", "Артемий", "Оля", "Маша"]
var reversedNames = names.sorted() { $0 > $1 }
reversedNames = names.sorted { $0 > $1 }
Array
в Swift имеет метод map(_:)
, который принимает замыкание в качестве своего единственного аргумента. Замыкание вызывается один раз для каждого элемента массива и возвращает поставленное ему в соответствие значение (возможно какого-то другого типа). Природа отображения и тип возвращаемого значения оставлены на откуп замыканию.
map(_:)
возвращает новый массив, содержащий все новые отображённые значения в том же порядке, что и корреспондирующие им значения оригинального массива.
map(_:)
с trailing-замыканием для конвертации массива Int
в массив значений String
. Массив [16, 58, 510] используется для создания нового массива ["OneSix", "FiveEight", "FiveOneZero"].
let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
let strings = numbers.map{ (number) -> String in
var number = number
var output = ""
repeat {
output = digitNames[number % 10]! + output
number /= 10
} while number > 0
return output
}
// strings выведено в тип [String]
// его значение равно ["OneSix", "FiveEight", "FiveOneZero"]
Теперь Вы можете использовать массив numbers для создания массива типа String
, передав в метод массива map(_:)
волочащееся замыкание.
map(_:)
вызывает замыкание единожды для каждого элемента в массиве. Вам не нужно явно указывать тип входного параметра замыкания, number
, так как этот тип может быть выведен из значений отображаемого массива.
number
инициализируется значением параметра замыкания number
, так что это значение может быть изменено внутри тела замыкания. (Параметры функций и замыканий всегда константы.) Замыкание так же специфицирует возвращаемый тип String
, чтобы указать, какиой тип будет храниться в отображённом выходном массиве.
output
всякий раз при своём вызове. Оно вычисляет последнюю цифру number
с использованием оператора остатка от деления (number % 10)
и использует эту цифру для выбора подходящей строки в словаре digitNames
. Это замыкание может быть использовано для создания строки, отображающей любое целое число, большее 0.
digitNames
сопровождается восклицательным знаком (!), так как сабскрипты словарей возвращают опциональное значение для индикации того, что выбор значения из словаря может провалиться, если указанный ключ не существует. В примере Выше гарантировано, что number % 10
всегда будет корректным ключом сабскрита для словаря digitNames
, так что восклицательный знак используется для принудительной распаковки значения типа String
, хранимого в опциональном возвращаемом значении сабскрипта.
digitNames
прибавляется в переднюю часть output
, эффективно создавая строковые представление числа в обратном порядке. (Выражение number % 10 даёт число 6 для 16, 8 для 58 и 0 для 510.)
number
затем делится на 10. Так как это целое число, то оо будет округлено вниз при делении, так что 16 станет 1, 58 станет 5, а 510 станет 51.
number
не станет равен 0, в этот момент строка output
будет возвращена замыканием и добавлена в выходной массив метода map(_:)
.
map(_:)
.