Как проверить, находится ли элемент в массиве

в Swift, как я могу проверить, существует ли элемент в массиве? Xcode не имеет никаких предложений для contain, include или has, и быстрый поиск по книге ничего не обнаружил. Есть идеи, как это проверить? Я знаю, что есть метод find это возвращает номер индекса, но есть ли метод, который возвращает логическое значение, такое как ruby's #include??

пример того, что мне нужно:

var elements = [1,2,3,4,5]
if elements.contains(5) {
  //do something
}

14 ответов


Swift 2, 3, 4:

let elements = [1, 2, 3, 4, 5]
if elements.contains(5) {
    print("yes")
}

contains() это метод расширения протокола of SequenceType (для последовательности Equatable elements), а не глобальный метод, как в предыдущие версии.

Примечания:

Swift старые версии:

let elements = [1,2,3,4,5]
if contains(elements, 5) {
    println("yes")
}

для тех, кто пришел сюда в поисках найти и удалить объект из массива:

Swift 1

if let index = find(itemList, item) {
    itemList.removeAtIndex(index)
}

Swift 2

if let index = itemList.indexOf(item) {
    itemList.removeAtIndex(index)
}

Swift 3, 4

if let index = itemList.index(of: item) {
    itemList.remove(at: index)
}

использовать это расширение:

extension Array {
    func contains<T where T : Equatable>(obj: T) -> Bool {
        return self.filter({ as? T == obj}).count > 0
    }
}

как использовать:

array.contains(1)

обновлено для Swift 2/3

обратите внимание, что с Swift 3 (или даже 2) расширение больше не требуется как глобальное contains функция была превращена в пару метода расширения на Array, которые позволяют вам делать либо из:

let a = [ 1, 2, 3, 4 ]

a.contains(2)           // => true, only usable if Element : Equatable

a.contains {  < 1 }   // => false

Если вы проверяете, является ли экземпляр пользовательский класс или struct содержится в массиве, вам понадобится использовать тег Equatable протокол, прежде чем вы можете использовать .содержит (myObject).

например:

struct Cup: Equatable {
    let filled:Bool
}

static func ==(lhs:Cup, rhs:Cup) -> Bool { // Implement Equatable
    return lhs.filled == rhs.filled
}

затем вы можете сделать:

cupArray.contains(myCup)

Совет: переопределение == должно быть на глобальном уровне, а не в вашем классе/структуре


я использовал фильтр.

let results = elements.filter { el in el == 5 }
if results.count > 0 {
    // any matching items are in results
} else {
    // not found
}

Если вы хотите, вы можете сжать это

if elements.filter({ el in el == 5 }).count > 0 {
}

надеюсь, что это поможет.


обновление для Swift 2

Ура для реализаций по умолчанию!

if elements.contains(5) {
    // any matching items are in results
} else {
    // not found
}

(Swift 3)

проверьте, существует ли элемент в массиве (удовлетворяющий некоторым критериям),и если да, продолжайте работать с первым таким элементом

если намерение является:

  1. чтобы проверить, существует ли элемент в массиве (/выполняет некоторые логические критерии, не обязательно равенство тестирования),
  2. и если это так, продолжайте и работайте с первым таким элементом,

затем альтернатива contains(_:) как blueprinted Sequence это first(where:) of Sequence:

let elements = [1, 2, 3, 4, 5]

if let firstSuchElement = elements.first(where: {  == 4 }) {
    print(firstSuchElement) // 4
    // ...
}

в этом надуманном примере его использование может показаться глупым, но это очень полезно, если запрашивать массивы неосновных типов элементов для существования каких-либо элементов, выполняющих какое-либо условие. Е. Г.

struct Person {
    let age: Int
    let name: String
    init(_ age: Int, _ name: String) {
        self.age = age
        self.name = name
    }
}

let persons = [Person(17, "Fred"),   Person(16, "Susan"),
               Person(19, "Hannah"), Person(18, "Sarah"),
               Person(23, "Sam"),    Person(18, "Jane")]

if let eligableDriver = persons.first(where: { .age >= 18 }) {
    print("\(eligableDriver.name) can possibly drive the rental car in Sweden.")
    // ...
} // Hannah can possibly drive the rental car in Sweden.

let daniel = Person(18, "Daniel")
if let sameAgeAsDaniel = persons.first(where: { .age == daniel.age }) {
    print("\(sameAgeAsDaniel.name) is the same age as \(daniel.name).")
    // ...
} // Sarah is the same age as Daniel.

любые цепные операции с использованием .filter { ... some condition }.first можно выгодно заменить на first(where:). Последний показывает намерение лучше и имеет производительность преимущества перед возможными не-ленивыми приборами .filter, поскольку они передадут полный массив до извлечения (возможного) первого элемента, проходящего фильтр.


проверьте, существует ли элемент в массиве (удовлетворяющий некоторым критериям),и если да, удалите первый такой элемент

комментарий ниже запросы:

как я могу удалить firstSuchElement из массива?

аналогичный случай использования к одному выше удалить первый элемент, который удовлетворяет заданному предикату. Для этого index(where:) метод Collection (который легко доступен для коллекции array) может использоваться для поиска индекса первого элемента, выполняющего предикат, после чего индекс может использоваться с remove(at:) метод Array to (возможно; учитывая, что он существует) удалите этот элемент.

var elements = ["a", "b", "c", "d", "e", "a", "b", "c"]

if let indexOfFirstSuchElement = elements.index(where: {  == "c" }) {
    elements.remove(at: indexOfFirstSuchElement)
    print(elements) // ["a", "b", "d", "e", "a", "b", "c"]
}

или, если вы хотите удалить элемент из массива С применить Optional: s map(_:) метод условно (для .some(...) вернуться из index(where:)) использовать результат index(where:) для удаления и захвата удаленного элемента из массива (в необязательном предложении binding).

var elements = ["a", "b", "c", "d", "e", "a", "b", "c"]

if let firstSuchElement = elements.index(where: {  == "c" })
    .map({ elements.remove(at: ) }) {

    // if we enter here, the first such element have now been
    // remove from the array
    print(elements) // ["a", "b", "d", "e", "a", "b", "c"]

    // and we may work with it
    print(firstSuchElement) // c
}

обратите внимание, что в надуманном примере члены массива являются простыми типами значений (String экземпляры), поэтому использование предиката для поиска данного члена несколько перебивает, так как мы может просто проверить равенство, используя simpler index(of:) метод, как показано в @DogCoffee это. Если применить подход "найти и удалить" выше к Person пример, однако, используя index(where:) с предикатом подходит (так как мы больше не тестируем на равенство, а для выполнения предоставленного предиката).


самый простой способ сделать это-использовать фильтр на массиве.

let result = elements.filter { ==5 }

result будет иметь найденный элемент, если он существует, и будет пустым, если элемент не существует. Так просто проверить, если result is empty сообщит Вам, существует ли элемент в массиве. Я бы использовал следующее:

if result.isEmpty {
    // element does not exist in array
} else {
    // element exists
}

по состоянию на Swift 2.1 NSArrays имеют containsObjectЭто можно использовать так:

if myArray.containsObject(objectImCheckingFor){
    //myArray has the objectImCheckingFor
}

на всякий случай, если кто-то пытается найти, если indexPath является одним из выбранных (например, в UICollectionView или UITableView cellForItemAtIndexPath функции):

    var isSelectedItem = false
    if let selectedIndexPaths = collectionView.indexPathsForSelectedItems() as? [NSIndexPath]{
        if contains(selectedIndexPaths, indexPath) {
            isSelectedItem = true
        }
    }

вот мое небольшое расширение, которое я только что написал, чтобы проверить, содержит ли мой массив делегатов объект делегата или нет ( Swift 2). :) Он также работает с типами значений как шарм.

extension Array
{
    func containsObject(object: Any) -> Bool
    {
        if let anObject: AnyObject = object as? AnyObject
        {
            for obj in self
            {
                if let anObj: AnyObject = obj as? AnyObject
                {
                    if anObj === anObject { return true }
                }
            }
        }
        return false
    }
}

Если у вас есть идея, как оптимизировать этот код, просто дайте мне знать.


Свифт

если вы не используете объект, вы можете использовать этот код для contains.

let elements = [ 10, 20, 30, 40, 50]

if elements.contains(50) {

   print("true")

}

если вы используете класс NSObject в swift. Эти переменные соответствуют моему требованию. вы можете доработать для вашего требования.

var cliectScreenList = [ATModelLeadInfo]()
var cliectScreenSelectedObject: ATModelLeadInfo!

Это для того же типа данных.

{ .user_id == cliectScreenSelectedObject.user_id }

если вы хотите тип AnyObject.

{ "\(.user_id)" == "\(cliectScreenSelectedObject.user_id)" }

полное условие

if cliectScreenSelected.contains( { .user_id == cliectScreenSelectedObject.user_id } ) == false {

    cliectScreenSelected.append(cliectScreenSelectedObject)

    print("Object Added")

} else {

    print("Object already exists")

 }

если пользователь находит определенные элементы массива, используйте ниже код, такой же, как целочисленное значение.

var arrelemnts = ["sachin", "test", "test1", "test3"]

 if arrelemnts.contains("test"){
    print("found")   }else{
    print("not found")   }

Swift 4, другой способ достичь этого, с функцией фильтра

var elements = [1,2,3,4,5]

    if let object = elements.filter({  == 5 }).first {
        print("found")
    } else {
        print("not found")
    }

как насчет использования хэш-таблицы для работы, как это?

во-первых, создание универсальной функции "хэш-карта", расширение протокола последовательности.

extension Sequence where Element: Hashable {

    func hashMap() -> [Element: Int] {
        var dict: [Element: Int] = [:]
        for (i, value) in self.enumerated() {
            dict[value] = i
        }
        return dict
    }
}

Это расширение будет работать столько, сколько элементов в массиве соответствует Hashable, как целые числа или строки, вот использование...

let numbers = Array(0...50) 
let hashMappedNumbers = numbers.hashMap()

let numToDetect = 35

let indexOfnumToDetect = hashMappedNumbers[numToDetect] // returns the index of the item and if all the elements in the array are different, it will work to get the index of the object!

print(indexOfnumToDetect) // prints 35

но пока давайте просто сосредоточимся на проверке, находится ли элемент в массиве.

let numExists = indexOfnumToDetect != nil // if the key does not exist 
means the number is not contained in the collection.

print(numExists) // prints true