Menu
Coddy logo textTech

Comparable

Часть раздела Объектно-ориентированное программирование путешествия по Swift на Coddy. Урок 39 из 57.

Comparable предоставляет типу операторы <, <=, > и >=. Вы реализуете только <; Swift выводит остальные. Типы, соответствующие Comparable, можно сортировать с помощью sorted() и использовать с min() и max():

struct Version: Comparable {
    let major: Int, minor: Int

    static func < (lhs: Version, rhs: Version) -> Bool {
        (lhs.major, lhs.minor) < (rhs.major, rhs.minor)
    }
}

let versions = [Version(major: 2, minor: 1), Version(major: 1, minor: 9), Version(major: 2, minor: 0)]
let newest = versions.max()!
print("\(newest.major).\(newest.minor)")
print(versions.sorted().map { "\($0.major).\($0.minor)" })

Вывод:

2.1
["1.9", "2.0", "2.1"]

Сравнение кортежей сравнивает их части по порядку, благодаря чему сравнения по нескольким ключам остаются короткими. Здесь задачи сортируются сначала по приоритету, а затем по имени:

struct Task: Comparable {
    let priority: Int
    let name: String

    static func < (lhs: Task, rhs: Task) -> Bool {
        (lhs.priority, lhs.name) < (rhs.priority, rhs.name)
    }
}

let tasks = [Task(priority: 2, name: "email"), Task(priority: 1, name: "fix"), Task(priority: 2, name: "call")]
print(tasks.sorted().map { $0.name })

Вывод:

["fix", "call", "email"]

Перечисления без связанных значений могут соответствовать Comparable без написания <: варианты сравниваются в порядке их объявления:

enum Priority: Comparable {
    case low, medium, high
}

print(Priority.low < Priority.high)
print([Priority.high, .low, .medium].sorted())

Вывод:

true
[main.Priority.low, main.Priority.medium, main.Priority.high]

sorted(by:) сортирует по любому правилу за один вызов, тогда как Comparable определяет естественный порядок типа, который sorted(), min() и max() используют повсюду:

struct Task: Comparable {
    let priority: Int
    let name: String
    static func < (lhs: Task, rhs: Task) -> Bool { lhs.priority < rhs.priority }
}

let tasks = [Task(priority: 3, name: "c"), Task(priority: 1, name: "a")]
print(tasks.sorted().map { $0.name })
print(tasks.sorted(by: >).map { $0.name })

Результат:

["a", "c"]
["c", "a"]
challenge icon

Задание

Легко

Сделайте так, чтобы Runner (имя и время финиша в виде minutes, seconds) соответствовал Comparable, при этом более быстрое время считается меньшим, а одинаковые времена упорядочиваются по имени. Реализуйте podium(_:): функция должна сортировать бегунов с помощью sorted() и возвращать строки вида 1. Ada 20:05 для первых трёх (меньше, если бегунов меньше), дополняя секунды до двух цифр.

Предоставленный код считывает строки в формате name,mm:ss и выводит каждую возвращённую строку.

Ваш код должен находиться в Runner.swift и Functions.swift. В main.swift содержится предоставленный код ввода/вывода, и его нельзя редактировать.

Попробуйте сами

// Предоставленный код ввода/вывода: оставьте его как есть
var input: [String] = []
while let line = readLine() { input.append(line) }
let runners = input.map { line -> Runner in
    let p = line.split(separator: ",").map(String.init)
    let t = p[1].split(separator: ":").map { Int($0)! }
    return Runner(name: p[0], minutes: t[0], seconds: t[1])
}
for line in podium(runners) { print(line) }
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Песочница Swift