Массив [Любой] и содержит ()

Я пытаюсь проверить, если массив типа [Any] содержит значение определенного типа (скажем, Int).

Я знаю, что Свифт не знает, как сравнить Int и значение произвольного типа, и я думаю, это то, что выражается в шаблоне автозаполнения:

contains(predicate: (protocol<>) throws -> Bool)

Итак, я попробовал этот код:

let intValue:Int = 5 // for example

let isContained = myArrayOfAny.contains({ element in 
    return ((element as? Int) == intValue)
})

... и он компилируется (пока не могу убедиться, что он работает); но до сих пор не может сделать головы или хвосты predicate: (protocol<>) часть. Что это значит? Документация для SequenceType довольно загадочно

contains(_: (Self.Generator.Element) throws -> Bool) rethrows -> Bool
 Default Implementation
Return true iff an element in self satisfies predicate.

Declaration
@warn_unused_result func contains(@noescape _ predicate: (Self.Generator.Element) throws -> Bool) rethrows -> Bool

РЕДАКТИРОВАТЬ: я довольно смущен, потому что все результаты поиска, которые я видел, имеют contains() метод Array как просто взятие значения, которое будет проверено на сдерживание, например:

if myArrayOfInt.contains(someInt){
    ...

а не закрытие.

1 ответ

Решение

Есть два разных contains() методы (оба расширения протокола для SequenceType). Первый

extension SequenceType where Generator.Element : Equatable {
    /// Return `true` iff `element` is in `self`.
    @warn_unused_result
    public func contains(element: Self.Generator.Element) -> Bool
}

и это требует, чтобы элементы последовательности соответствовали Equatableпротокол, который гарантирует, что их можно сравнить с ==:

public protocol Equatable {
    // ...
    public func ==(lhs: Self, rhs: Self) -> Bool
}

Например, в

let intValue:Int = 5
let myArrayOfInt = [4, 5, 6]
let isContained = myArrayOfInt.contains(intValue)

у вас есть массив Int, а также Int соответствует Equatableтак вот contains() Метод может быть использован для проверки наличия определенного элемента.

Это не работает для

let myArrayOfAny : [Any] = [4, 5, 6]

так как Any не соответствует Equatable, Здесь вы можете использовать второй contains() метод

extension SequenceType {
    /// Return `true` iff an element in `self` satisfies `predicate`.
    @warn_unused_result
    public func contains(@noescape predicate: (Self.Generator.Element) throws -> Bool) rethrows -> Bool
}

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

И это то, что вы делаете в

let myArrayOfAny : [Any] = [4, 5, 6]
let intValue:Int = 5 // for example
let isContained = myArrayOfAny.contains({ element in 
    return ((element as? Int) == intValue)
})

Это даст true если любой элемент массива может быть приведен к Intи равен данному intValue,

Возможно, первый метод встречается чаще, а второй гораздо более общий, например,

if myArrayOfCustomObjects.contains ({ $0.someProperty == "foo" })

или же

if myArrayOfInts.contains ({ $0 > 17 })

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

extension SequenceType where Generator.Element : Equatable {

    public func contains(element: Self.Generator.Element) -> Bool {
        return self.contains({ $0 == element } )
    }
}

Вы найдете то же самое с indexOf() который также поставляется в двух вариантах:

extension CollectionType where Generator.Element : Equatable {
    // ...
    public func indexOf(element: Self.Generator.Element) -> Self.Index?
}

extension CollectionType {
    // ...
    public func indexOf(@noescape predicate: (Self.Generator.Element) throws -> Bool) rethrows -> Self.Index?
}
Другие вопросы по тегам