Найти объект в массиве?

Есть ли у Swift что-то вроде _. findWhere в Underscore.js?

У меня есть массив структур типа T и хотел бы проверить, содержит ли массив объект struct, свойство name равно Foo.

Пытался использовать find() и filter(), но они работают только с примитивными типами, например. String или Int. Выдает сообщение об ошибке, не соответствующей протоколу Equitable или тому подобному.

Ответ 1

FWIW, если вы не хотите использовать пользовательскую функцию или расширение, вы можете:

let array = [ .... ]
if let found = find(array.map({ $0.name }), "Foo") {
    let obj = array[found]
}

Сначала создается массив name, затем find от него.

Если у вас огромный массив, вы можете сделать это:

if let found = find(lazy(array).map({ $0.name }), "Foo") {
    let obj = array[found]
}

или возможно:

if let found = find(lazy(array).map({ $0.name == "Foo" }), true) {
    let obj = array[found]
}

Ответ 2

SWIFT 5

Проверьте, существует ли элемент

if array.contains(where: {$0.name == "foo"}) {
   // it exists, do something
} else {
   //item could not be found
}

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

if let foo = array.first(where: {$0.name == "foo"}) {
   // do something with foo
} else {
   // item could not be found
}

Получить элемент и его смещение

if let foo = array.enumerated().first(where: {$0.element.name == "foo"}) {
   // do something with foo.offset and foo.element
} else {
   // item could not be found
}

Получить смещение

if let fooOffset = array.firstIndex(where: {$0.name == "foo"}) {
    // do something with fooOffset
} else {
    // item could not be found
}

Ответ 3

Вы можете использовать метод index, доступный в Array, с предикатом (см. Документацию Apple здесь).

func index(where predicate: (Element) throws -> Bool) rethrows -> Int?

Для вашего конкретного примера это будет:

Swift 5.0

if let i = array.firstIndex(where: { $0.name == "Foo" }) {
    return array[i]
}

Swift 3.0

if let i = array.index(where: { $0.name == Foo }) {
    return array[i]
}

Swift 2.0

if let i = array.indexOf({ $0.name == Foo }) {
    return array[i]
}

Ответ 4

Swift 3

Если вам нужно использовать объект:

array.first{$0.name == "Foo"}

(Если у вас есть несколько объектов с именем "Foo", то first вернет первый объект из неуказанного порядка)

Ответ 5

Swift 3.0

if let index = array.index(where: { $0.name == "Foo" }) {
    return array[index]
}

Swift 2.1

Фильтрация в свойствах объекта теперь поддерживается в Swift 2.1. Вы можете фильтровать ваш массив на основе любого значения структуры или класса, вот пример

for myObj in myObjList where myObj.name == "foo" {
 //object with name is foo
}

ИЛИ ЖЕ

for myObj in myObjList where myObj.Id > 10 {
 //objects with Id is greater than 10
}

Ответ 6

Вы можете фильтровать массив, а затем просто выбрать первый элемент, как показано в Найти объект с использованием свойства в массиве.

Или вы определяете настраиваемое расширение

extension Array {

    // Returns the first element satisfying the predicate, or `nil`
    // if there is no matching element.
    func findFirstMatching<L : BooleanType>(predicate: T -> L) -> T? {
        for item in self {
            if predicate(item) {
                return item // found
            }
        }
        return nil // not found
    }
}

Пример использования:

struct T {
    var name : String
}

let array = [T(name: "bar"), T(name: "baz"), T(name: "foo")]

if let item = array.findFirstMatching( { $0.name == "foo" } ) {
    // item is the first matching array element
} else {
    // not found
}

В Swift 3 вы можете использовать существующий метод first(where:) (как упомянутый в комментарии):

if let item = array.first(where: { $0.name == "foo" }) {
    // item is the first matching array element
} else {
    // not found
}

Ответ 7

Swift 3

вы можете использовать индекс (где:) в Swift 3

func index(where predicate: @noescape Element throws -> Bool) rethrows -> Int?

Пример

if let i = theArray.index(where: {$0.name == "Foo"}) {
    return theArray[i]
}

Ответ 8

Swift 4,

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

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

Ответ 9

Swift 3

if yourArray.contains(item) {
   //item found, do what you want
}
else{
   //item not found 
   yourArray.append(item)
}

Ответ 10

Swift 2 или более поздняя версия

Вы можете объединить indexOf и map, чтобы написать функцию "найти элемент" в одной строке.

let array = [T(name: "foo"), T(name: "Foo"), T(name: "FOO")]
let foundValue = array.indexOf { $0.name == "Foo" }.map { array[$0] }
print(foundValue) // Prints "T(name: "Foo")"

Использование filter + first выглядит более чистым, но filter оценивает все элементы в массиве. indexOf + map выглядит сложным, но оценка останавливается, когда найдено первое совпадение в массиве. Оба подхода имеют свои плюсы и минусы.

Ответ 11

Используйте contains:

var yourItem:YourType!
if contains(yourArray, item){
    yourItem = item
}

Или вы могли бы попробовать, на что Мартин указал вам, в комментариях и дать filter еще одну попытку: Найти объект с собственностью в массиве.

Ответ 12

Другой способ получить доступ к array.index(из: Any) - объявить ваш объект

import Foundation
class Model: NSObject {  }

Ответ 13

Используйте Dollar, который является Lo-Dash или Underscore.js для Swift:

import Dollar

let found = $.find(array) { $0.name == "Foo" }

Ответ 14

Swift 3:

Вы можете использовать встроенные функции Swift для поиска пользовательских объектов в массиве.

Сначала вы должны убедиться, что ваш пользовательский объект соответствует: Equatable protocol.

class Person : Equatable { //<--- Add Equatable protocol
    let name: String
    var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }

    //Add Equatable functionality:
    static func == (lhs: Person, rhs: Person) -> Bool {
        return (lhs.name == rhs.name)
    }
}

При использовании Equatable функциональности, добавленной к вашему объекту, Swift теперь покажет вам дополнительные свойства, которые вы можете использовать в массиве:

//create new array and populate with objects:
let p1 = Person(name: "Paul", age: 20)
let p2 = Person(name: "Mike", age: 22)
let p3 = Person(name: "Jane", age: 33)
var people = [Person]([p1,p2,p3])

//find index by object:
let index = people.index(of: p2)! //finds Index of Mike

//remove item by index:
people.remove(at: index) //removes Mike from array

Ответ 15

Для Swift 3,

let index = array.index(where: {$0.name == "foo"})

Ответ 16

Например, если у нас был массив чисел:

let numbers = [2, 4, 6, 8, 9, 10]

Мы могли бы найти первое нечетное число, как это:

let firstOdd = numbers.index { $0 % 2 == 1 }

Это вернет 4 в качестве необязательного целого числа, потому что первое нечетное число (9) находится в индексе четыре.