Фильтровать массив элементов по свойству enum со связанным значением

class MyClass: Decodable {

    let title: String?
    let type: MyClass.MyType?

    enum MyType {
        case article(data: [Article])
        case link(data: [LinkTile])
        case none
    }
}

Я хотел бы отфильтровать массив MyClass элементы, поэтому фильтрованный массив не будет содержать экземпляры с типом .none

let filteredArray = array.filter { $0.type != .none } // this doesn't work

2 ответа

Решение

К сожалению, вы не можете использовать == с участием enumс соответствующими значениями. Вы должны использовать сопоставление с образцом, но это должно быть сделано в switch или же if заявление.

Итак, это приводит к чему-то ужасному:

let filteredArray = array.filter { if case .none = $0.type! { return false }; return true }

Примечания:

  1. Вы не можете назвать свой enumType потому что это конфликтует со встроенным Type, Измените это на что-то вроде MyType,

  2. Это очень запутанно использовать none как случай в обычае enum потому что это путается (людьми) с none в необязательном. Это усугубляется тем, что ваш type свойство необязательно. Здесь я развернул его силой, но это, конечно, опасно.

    Вы могли бы сделать:

    if case .none? = $0.type
    

    Это будет соответствовать none дело явно и лечить nil как то, что вы хотите сохранить.

    Отфильтровать nil а также .none, вы можете использовать оператор слияния ноль ??:

    if case .none = ($0.type ?? .none)
    

    Я бы предложил объявить type как MyClass.MyType вместо MyClass.MyType?,

Я сделал вам простой пример того, как использовать enum в вашем контексте с функцией фильтра.

enum Foo {

  case article(data: [Int])
  case link(data: [String])
  case `none`

  static func myfilter(array: [Foo]) -> [Foo]{
    var newArray:[Foo] = []
    for element in array {
      switch element {
      case .article(let article):
        newArray.append(.article(data: article))
      case .link(let link):
        newArray.append(.link(data: link))
      case .none:
        break
      }
    }
    return newArray
  }
}

let foo: [Foo] = [.article(data: [1,2,3]), .link(data: ["hello", "world"]), .none]

print(Foo.myfilter(array: foo))

Я сделал код, который вы можете скомпилировать и протестировать, вы должны изменить тип для Foo, articleа также link,

Если вы хотите использовать перечисление, вы должны использовать switch case,

Если вы абсолютно хотите использовать фильтр в swift, вы можете, но вам нужно реализовать Sequence протокола, который в этом случае является более сложным.

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

Другие вопросы по тегам