28

Currently, I have an array of objects like this:

var myArr = [
  MyObject(name: "Abc", description: "Lorem ipsum 1."),
  MyObject(name: "Def", description: "Lorem ipsum 2."),
  MyObject(name: "Xyz", description: "Lorem ipsum 3.")
]

I am testing if an object exists before proceeding like this:

let item = myArr.filter { $0.name == "Def" }.first
if item != nil {
  // Do something...
}

But I'm looking for a shorter way to do this since I am doing this a lot. I'd like to do something like this but it is invalid:

if myArr.contains { $0.name == "Def" } {
  // Do something...
}

Is there any shorthand syntax I'm missing or a better way to do this?

TruMan1
  • 33,665
  • 59
  • 184
  • 335
  • How does this question differ from [this one](http://stackoverflow.com/q/29678071/148357)? They look pretty much the same – Antonio Apr 16 '15 at 15:38
  • Same array, totally different question. I'm asking for a boolean to give me if an item exists in an array. Other questions is how to remove it from an array. – TruMan1 Apr 16 '15 at 15:39
  • I'm learning and picking at Swift. Seems like I have to everything the long way, remove, contains, find, etc. I've been spoiled by Underscore.js and was hoping there was something like it in Swift: http://underscorejs.org – TruMan1 Apr 16 '15 at 15:48
  • 1
    I've also been spoiled by built-in lambda expressions in C# :( – TruMan1 Apr 16 '15 at 15:49
  • 1
    But have you been so spoiled that you can't bother to read the documentation or learn the language? – matt Apr 16 '15 at 15:53
  • Ok ok I'll extend the language :). I have been reading the docs but supplementing with learning from people too. Thanks for sharing really. – TruMan1 Apr 16 '15 at 16:09
  • Found this awesome Swift library that is a port of Underscore.js that can do many of these things: http://www.dollarswift.org – TruMan1 May 27 '15 at 16:00

2 Answers2

58

Why not use the built-in contains() function? It comes in two flavors

func contains<S : SequenceType, L : BooleanType>(seq: S, predicate: @noescape (S.Generator.Element) -> L) -> Bool
func contains<S : SequenceType where S.Generator.Element : Equatable>(seq: S, x: S.Generator.Element) -> Bool

and the first one takes a predicate as argument.

if contains(myArr, { $0.name == "Def" }) {
    println("yes")
}

Update: As of Swift 2, both global contains() functions have been replaced by protocol extension methods:

extension SequenceType where Generator.Element : Equatable {
    func contains(element: Self.Generator.Element) -> Bool
}

extension SequenceType {
    func contains(@noescape predicate: (Self.Generator.Element) -> Bool) -> Bool
}

and the first (predicate-based) one is used as:

if myArr.contains( { $0.name == "Def" }) {
    print("yes")
}

Swift 3:

if myArr.contains(where: { $0.name == "Def" }) {
    print("yes")
}
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
2

IMHO to achieve the desired behavior you would have to create an extension class to the array that would look something like:

extension Array {
    func contains(test: (T) -> Bool, action: (T) -> Void) {
        let filtered = self.filter(test)
        if(filtered.is​Empty) {
            action(filtered)
        }
    }
}

I don't have xcode in front of me so I apologize if i have a syntax error. However if you are using the often you can write it as follows

myArr.contains({ $0.name == "Def"}) {
   // Do something...
}

I would rename it as to prevent confusion in your code.

Nathan
  • 201
  • 1
  • 7
  • Correct me if I'm wrong, but won't `self.filter(test)` produce an empty array if none of the elements pass the test, therefore never being nil in this case? – Josh Paradroid Apr 05 '17 at 12:27
  • I can update the answer seeing as one would just need to check the size of the array, although Apple now includes functionality that fits the individuals need. – Nathan Apr 06 '17 at 13:57