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

476

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

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

var elements = [1,2,3,4,5]
if elements.contains(5) {
  //do something
}
jaredsmith
источник
11
if find(elements, 5) != nil { }не достаточно хорош?
Мартин Р
1
Я надеялся на что-то более чистое, но это не выглядит хорошо. Я ничего не нашел ни в документации, ни в книге.
Джаредмит

Ответы:

861

Свифт 2, 3, 4, 5:

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

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

Примечания:

Swift более старые версии:

let elements = [1,2,3,4,5]
if contains(elements, 5) {
    println("yes")
}
Мартин Р
источник
4
Любая документация об этом типе глобальных функций?
Ривера
3
Должно ли это работать, если каждый элемент в массиве (и элемент, который мы ищем) имеет тип Dictionary <String, AnyObject>? Пытаясь добиться этого, но я получаю ошибку во время компиляции.
ppalancica
7
@ppalancica: для этого необходимо, чтобы элементы массива соответствовали Equatableпротоколу (а Dictionary<String, AnyObject>это не так). Есть второй вариант, contains()который принимает предикат (сравните stackoverflow.com/questions/29679486/… ), возможно, вы можете использовать это, напримерif contains(array, { $0 == dict } ) ...
Martin R
Как искать конкретный элемент из общего массива? сказать [AnyObject]?
Давал Х. Нена
127

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

Свифт 1

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

Swift 2

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

Свифт 3, 4

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

Swift 5.2

if let index = itemList.firstIndex(of: item) {
    itemList.remove(at: index)
}
DogCoffee
источник
3
Пожалуйста, ответьте на соответствующий вопрос. Этот вопрос просто касается поиска элемента в массиве, а не его удаления или обновления. Вы можете задать отдельный вопрос и ответить на него самостоятельно.
Tejas
60

Используйте это расширение:

extension Array {
    func contains<T where T : Equatable>(obj: T) -> Bool {
        return self.filter({$0 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 { $0 < 1 }   // => false
Дэвид Берри
источник
10
найти быстрее.
Джим Балтер
1
в зависимости от того, к чему вы привыкли, .contains может показаться более интуитивным и запоминающимся
Pirijan
4
Не могли бы вы объяснить свой синтаксис, разбив его? Я никогда раньше не видел такого форматирования, и у тебя сразу много чего происходит!
Агрессор
40

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

Например:

struct Cup: Equatable {
    let filled:Bool
}

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

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

cupArray.contains(myCup)

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

Эндрю Шрайбер
источник
32

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

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, использующая фильтр в этом поле.
Мори Марковиц
Фильтр неэффективен, потому что он всегда зацикливается на всех элементах, а не сразу возвращается, когда элемент найден. Вместо этого лучше использовать find ().
Торстен
19

(Свифт 3)

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

Если целью является:

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

Тогда альтернатива , contains(_:)как blueprinted Sequenceявляется first(where:)из Sequence:

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

if let firstSuchElement = elements.first(where: { $0 == 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: { $0.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: { $0.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(который легко доступен для сбора массивов), чтобы найти индекс первого элемента, выполняющего предикат, после чего индекс можно использовать с remove(at:)методом Arrayto (возможно; при условии, что он существует) удалить этот элемент.

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

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

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

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

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

    // 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экземпляры), поэтому использование предиката для поиска заданного члена несколько избыточно, поскольку мы могли бы просто проверить на равенство, используя более простой index(of:)метод, как показано в ответе @ DogCoffee's. , Однако, если применить вышеописанный подход к поиску и удалению Person, index(where:)то целесообразно использовать с предикатом (поскольку мы больше не проверяем равенство, а выполняем предоставленный предикат).

dfri
источник
Как я могу удалить firstSuchElement из массива?
i6x86
@ i6x86 спасибо за вопрос. Я обновил свой ответ примером того, как удалить элемент (а также как удалить и зафиксировать удаленный элемент).
17
14

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

let result = elements.filter { $0==5 }

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

if result.isEmpty {
    // element does not exist in array
} else {
    // element exists
}
davetw12
источник
отличное решение. поэтому этот метод возвращает массив. Тем не менее, я использую это, чтобы искать «идентификатор». В моем приложении d уникальны, поэтому может быть только один результат. Есть ли способ вернуть только 1 результат? Сейчас я использую результат [0]
Дэн Болье,
3
@DanBeaulieu Делать что-то вроде let result = elements.filter { $0==5 }.firstдолжно выполнить то, что вы ищете.
davetw12
7

Свифт 4/5

Еще один способ добиться этого с помощью функции фильтра

var elements = [1,2,3,4,5]
if let object = elements.filter({ $0 == 5 }).first {
    print("found")
} else {
    print("not found")
}
Прамод Море
источник
6

Начиная с Swift 2.1 NSArrays containsObjectможно использовать следующим образом:

if myArray.containsObject(objectImCheckingFor){
    //myArray has the objectImCheckingFor
}
ColossalChris
источник
4
На самом деле это для NSArray. Не быстрый массив
Tycho Pandelaar
Да, но вы можете временно преобразовать ваш swift-массив в NSArray: если разрешить tempNSArrayForChecking = mySwiftArray в качестве NSArray? где tempNSArrayForChecking.containsObject (objectImCheckingFor) {// myArray имеет объект}
Виталий
4

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

    var isSelectedItem = false
    if let selectedIndexPaths = collectionView.indexPathsForSelectedItems() as? [NSIndexPath]{
        if contains(selectedIndexPaths, indexPath) {
            isSelectedItem = true
        }
    }
Али
источник
4

массив

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

Проверьте наличие элементов

elements.contains(5) // true

Получить индекс элементов

elements.firstIndex(of: 5) // 4
elements.firstIndex(of: 10) // nil

Получить количество элементов

let results = elements.filter { element in element == 5 }
results.count // 2
Саззад Хисейн Хан
источник
3

Вот мое небольшое расширение, которое я только что написал, чтобы проверить, содержит ли мой массив делегатов объект делегата или нет ( 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
    }
}

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

DevAndArtist
источник
2

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

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

 if arrelemnts.contains("test"){
    print("found")   }else{
    print("not found")   }
Йогеш шелке
источник
2

стриж

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

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

if elements.contains(50) {

   print("true")

}

Если вы используете NSObject Class в Swift. Эта переменная соответствует моему требованию. Вы можете изменить по вашему требованию.

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

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

{ $0.user_id == cliectScreenSelectedObject.user_id }

Если вы хотите, чтобы AnyObject типа.

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

Полное состояние

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

    cliectScreenSelected.append(cliectScreenSelectedObject)

    print("Object Added")

} else {

    print("Object already exists")

 }
Анит Кумар
источник
1

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

во-первых, создание универсальной функции «карты хешей», расширяющей протокол Sequence.

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
Джеймс Рочабрун
источник
0

Swift 4.2 +
Вы можете легко проверить, является ли ваш экземпляр массивом или нет, с помощью следующей функции.

func verifyIsObjectOfAnArray<T>(_ object: T) -> Bool {
   if let _ = object as? [T] {
      return true
   }

   return false
}

Даже вы можете получить к нему доступ следующим образом. Вы получите, nilесли объект не будет массивом.

func verifyIsObjectOfAnArray<T>(_ object: T) -> [T]? {
   if let array = object as? [T] {
      return array
   }

   return nil
}
Киран Джасвани
источник