Общий метод next () и previous () для CaseItearble - PullRequest
0 голосов
/ 20 марта 2019

Предположим, у нас есть перечисление и мы хотим перечислить его :). Если он имеет Int rawValue, мы можем получить следующий и предыдущий элементы, используя вычисленные переменные, подобные этому.

enum Fidelity: Int, CaseIterable { 
    case pixel
    case point
    case average
    case datapoint

    var previousFidelity: Fidelity {
        return Fidelity(rawValue: rawValue - 1) ?? .pixel
    }
    var nextFidelity: Fidelity {
        return Fidelity(rawValue: rawValue + 1) ?? .datapoint
    }
}

Я пошел дальше и создал и расширение для CaseIterable, которое позволяет next () и previous () для широкого диапазона типов.

// Let's test Swift 4.2 for enumerating enum
// Too complex, not very efficient, but interesting
extension CaseIterable where Self: Equatable  { 
    func next() -> Self? {
        let all = Self.allCases
        let idx = all.index(of: self)!
        let next = all.index(after: idx)
        return (next == all.endIndex) ? nil : all[next]
    }
    func previous() -> Self? {
        let all_reversed = Self.allCases.reversed()
        let idx = all_reversed.index(of: self)!
        let next = all_reversed.index(after: idx)
        return (next == all_reversed.endIndex) ? nil : all_reversed[next]
    }
}

Вопрос в том, насколько эффективны или неэффективны мои решения (т.е. скорость, память)? Есть ли какие-либо идеи для того, чтобы сделать те же или похожие вещи, возможно, offset(by: ).

1 Ответ

1 голос
/ 20 марта 2019

Вы можете реализовать previous(), используя offsetBy следующим образом:

func previous() -> Self? {
    let all = Self.allCases
    var idx = all.index(of: self)!

    if idx == all.startIndex {
        return nil
    } else {
        all.formIndex(&idx, offsetBy: -1)
        return all[idx]
    }
}

Вы можете комбинировать next() и previous() в более общей функции смещения:

extension CaseIterable where Self: Equatable  {
    func advanced(by n: Int) -> Self? {
        let all = Self.allCases
        let idx = all.index(of: self)!
        //An enum with a raw type has at least one case
        let lastIndex = all.index(all.endIndex, offsetBy: -1)
        let limit = n > 0 ? lastIndex : all.startIndex
        if let newIndex = all.index(idx, offsetBy: n, limitedBy: limit) {
            return all[newIndex]
        } else {
            return nil
        }
    }
}

И пользуйся вот так

let average = Fidelity.average  //average
average.advanced(by: 1)         //datapoint
average.advanced(by: 2)         //nil
average.advanced(by: -3)        //pixel
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...