Найти объект в массиве?
Есть ли у 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) находится в индексе четыре.