Find an object in array?
IosSwiftIos Problem Overview
Does Swift have something like _.findWhere in Underscore.js?
I have an array of structs of type T
and would like to check if array contains a struct object whose name
property is equal to Foo
.
Tried to use find()
and filter()
but they only work with primitive types, e.g. String
or Int
. Throws an error about not conforming to Equitable
protocol or something like that.
Ios Solutions
Solution 1 - Ios
SWIFT 5
Check if the element exists
if array.contains(where: {$0.name == "foo"}) {
// it exists, do something
} else {
//item could not be found
}
Get the element
if let foo = array.first(where: {$0.name == "foo"}) {
// do something with foo
} else {
// item could not be found
}
Get the element and its offset
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
}
Get the offset
if let fooOffset = array.firstIndex(where: {$0.name == "foo"}) {
// do something with fooOffset
} else {
// item could not be found
}
Solution 2 - Ios
You can use the index
method available on Array
with a predicate (see Apple's documentation here).
func index(where predicate: (Element) throws -> Bool) rethrows -> Int?
For your specific example this would be:
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]
}
Solution 3 - Ios
FWIW, if you don't want to use custom function or extension, you can:
let array = [ .... ]
if let found = find(array.map({ $0.name }), "Foo") {
let obj = array[found]
}
This generates name
array first, then find
from it.
If you have huge array, you might want to do:
if let found = find(lazy(array).map({ $0.name }), "Foo") {
let obj = array[found]
}
or maybe:
if let found = find(lazy(array).map({ $0.name == "Foo" }), true) {
let obj = array[found]
}
Solution 4 - Ios
Swift 3
If you need the object use:
array.first{$0.name == "Foo"}
(If you have more than one object named "Foo" then first
will return the first object from an unspecified ordering)
Solution 5 - Ios
You can filter the array and then just pick the first element, as shown in https://stackoverflow.com/questions/26073331/find-object-with-property-in-array.
Or you define a custom extension
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
}
}
Usage example:
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
}
In Swift 3 you can use the existing first(where:)
method
(as mentioned in a comment):
if let item = array.first(where: { $0.name == "foo" }) {
// item is the first matching array element
} else {
// not found
}
Solution 6 - Ios
Swift 3.0
if let index = array.index(where: { $0.name == "Foo" }) {
return array[index]
}
Swift 2.1
Filtering in object properties is now supported in swift 2.1. You can filter your array based on any value of the struct or class here is an example
for myObj in myObjList where myObj.name == "foo" {
//object with name is foo
}
OR
for myObj in myObjList where myObj.Id > 10 {
//objects with Id is greater than 10
}
Solution 7 - Ios
Swift 4,
Another way to achieve this using filter function,
if let object = elements.filter({ $0.title == "title" }).first {
print("found")
} else {
print("not found")
}
Solution 8 - Ios
Swift 3
you can use index(where:) in Swift 3
func index(where predicate: @noescape Element throws -> Bool) rethrows -> Int?
example
if let i = theArray.index(where: {$0.name == "Foo"}) {
return theArray[i]
}
Solution 9 - Ios
Swift 2 or later
You can combine indexOf
and map
to write a "find element" function in a single line.
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")"
Using filter
+ first
looks cleaner, but filter
evaluates all the elements in the array. indexOf
+ map
looks complicated, but the evaluation stops when the first match in the array is found. Both the approaches have pros and cons.
Solution 10 - Ios
Another way to get access to array.index(of: Any) is by declaring your object
import Foundation
class Model: NSObject { }
Solution 11 - Ios
Swift 3
if yourArray.contains(item) {
//item found, do what you want
}
else{
//item not found
yourArray.append(item)
}
Solution 12 - Ios
Use contains
:
var yourItem:YourType!
if contains(yourArray, item){
yourItem = item
}
Or you could try what Martin pointed you at, in the comments and give filter
another try: https://stackoverflow.com/questions/26073331/find-object-with-property-in-array.
Solution 13 - Ios
Swift 3:
You can use Swifts built in functionality to find custom objects in an Array.
First you must make sure your custom object conforms to the: 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)
}
}
With Equatable functionality added to your object , Swift will now show you additional properties you can use on an array:
//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
Solution 14 - Ios
For Swift 3,
let index = array.index(where: {$0.name == "foo"})
Solution 15 - Ios
Use Dollar which is Lo-Dash or Underscore.js for Swift:
import Dollar
let found = $.find(array) { $0.name == "Foo" }
Solution 16 - Ios
For example, if we had an array of numbers:
let numbers = [2, 4, 6, 8, 9, 10]
We could find the first odd number like this:
let firstOdd = numbers.index { $0 % 2 == 1 }
That will send back 4 as an optional integer, because the first odd number (9) is at index four.