10

I've had troubles filtering array of keywords (strings) in swift ,My code:

self.filteredKeywords=filter(keywords.allValues, {(keyword:NSString) ->                                              
  Bool in
    let words=keyword as? NSString
    return words?.containsString(searchText)
  })

As AnyObject can't be subtype of NSString, I'm stuck with this!

4
  • What is the exact error you get? What is printed if you try NSLog("\(keywords)")? Commented Apr 4, 2015 at 15:40
  • Just notice that you are returning an optional. Hope this helps Commented Apr 4, 2015 at 15:47
  • it doesn't run it gives me the error mentioned above : "AnyObject isn't a subtype of NSString" Commented Apr 4, 2015 at 16:26
  • Did either of the below answers answer your question? Commented Dec 28, 2015 at 15:57

4 Answers 4

16

[Updated for Swift 2.0]

As NSString is toll-free bridged to Swift String, just avoid the coercions with:

  3> ["abc", "bcd", "xyz"].filter() { nil != $0.rangeOfString("bc") }
$R1: [String] = 2 values {
  [0] = "abc"
  [1] = "bcd"
}

But, if you think allValues aren't strings:

(keywords.allValues as? [String]).filter() { nil != $0.rangeOfString("bc") }

which returns an optional array.

Sign up to request clarification or add additional context in comments.

Comments

4

Your filter is over [AnyObject], but your closure takes NSString. These need to match. Also, your result needs to be a Bool, not a Bool?. You can address these simply like this:

self.filteredKeywords = filter(keywords.allValues, {
    let keyword = $0 as? NSString
    return keyword?.containsString(searchText) ?? false
})

This accepts AnyObject and then tries to coerce it down to NSString. It then nil-coalleces (??) the result to make sure it always is a Bool.

I'd recommend, though, treating keywords as a [String:String] rather than an NSDictionary. That would get rid of all the complications of AnyObject. Then you can just do this:

self.filteredKeywords = keywords.values.filter { $0.rangeOfString(searchText) != nil }

Whenever possible, convert Foundation collections into Swift collections as soon as you can and store those. If you have incoming Foundation objects, you can generally convert them easily with techniques like:

let dict = nsdict as? [String:String] ?? [:]

Or you can do the following to convert them such that they'll crash in debug (but silently "work" in release):

func failWith<T>(msg: String, value: T) -> T {
    assertionFailure(msg)
    return value
}

let dict = nsdict as? [String:String] ?? failWith("Couldn't convert \(d)", [:])

Comments

1

Swift 4.2 provides a new way to do this:

var theBigLebowski = ["The Dude", "Angry Walter", "Maude Lebowski", "Donny Kerabatsos", "The Big Lebowski", "Little Larry Sellers"]

// after removeAll -> ["The Dude", "Angry Walter", "Donny Kerabatsos", "Little Larry Sellers"]
theBigLebowski.removeAll{ $0.contains("Lebowski")}
print(theBigLebowski)

Comments

0

There is both a problem with GoZoner's answer for certain data types and also a slightly better way to do this. The following examples can show this:

let animalArray: NSMutableArray = ["Dog","Cat","Otter","Deer","Rabbit"]
let filteredAnimals = animalArray.filter { $0.rangeOfString("er") != nil }
print("filteredAnimals:", filteredAnimals)

filteredAnimals: [Dog, Cat, Otter, Deer, Rabbit]

Likely not the set you expected!

However this works fine this way if we don't type animalArray as an NSMutableArray:

let animalArray = ["Dog","Cat","Otter","Deer","Rabbit"]
let filteredAnimals = animalArray.filter { $0.rangeOfString("er") != nil }
print("filteredAnimals:", filteredAnimals)

filteredAnimals: [Otter, Deer]

However I'd recommend using $0.contains() instead of $0.rangeOfString() != nil because it functions in both circumstances and slightly enhances the readability of the code:

let animalArray: NSMutableArray = ["Dog","Cat","Otter","Deer","Rabbit"]
let filteredAnimals = animalArray.filter { $0.contains("er") }
print("filteredAnimals:", filteredAnimals)

filteredAnimals: [Otter, Deer]

1 Comment

what if you had an array of filters like mime types to apply to a string instead of just one string to filter like "er"? filter=["stuff", "bear", "bottle"]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.