40

If my main array is ["Hello","Bye","Halo"], and I'm searching for "lo", it will filter the array only to ["Hello", "Halo"].

This is what I've tried:

 let matchingTerms = filter(catalogNames) {
        $0.rangeOfString(self.txtField.text!, options: .CaseInsensitiveSearch) !=  nil
    }

It throws

Type of expression is ambiguous without more context

Any suggestions?

7 Answers 7

119

Use contains instead:

let arr = ["Hello","Bye","Halo"]
let filtered = arr.filter { $0.contains("lo") }
print(filtered)

Output

["Hello", "Halo"]

Thanks to @user3441734 for pointing out that functionality is of course only available when you import Foundation

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

4 Comments

.. and don't forget import Foundation
@user3441734 thanks, you are right about that one - always forget the imports because they are already in the project.
how to add more than one condition in this ? e.g. let filtered = arr.filter { $0.containsString("lo") OR $0.containsString("ll") } Will work this ?
you need to plug in lowercased() for better results
35

In Swift 3.0

let terms = ["Hello","Bye","Halo"]

var filterdTerms = [String]()


func filterContentForSearchText(searchText: String) {
    filterdTerms = terms.filter { term in
        return term.lowercased().contains(searchText.lowercased())
    }
}


filterContentForSearchText(searchText: "Lo")
print(filterdTerms)

Output

["Hello", "Halo"]

5 Comments

He asked for swift two syntax. What is the point of providing a swift3 answer?
When some one search for filter string array only, he/she will get answer as well as may update knowledge of syntax in upgraded version
I think it was asked for Swift 2, cose of it was actual at that moment, now we working with Swift 3 so it's more valuable for this moment.
@GhostCat because people like me come from Google looking for Swift 3 solutions :)
this is giving me error in playground Value of type 'String' ha no member 'contains'
10

Swift 3.1

let catalogNames = [ "Hats", "Coats", "Trousers" ]
let searchCatalogName = "Hats"

let filteredCatalogNames = catalogNames.filter { catalogName in 
    return catalogName.localizedCaseInsensitiveContains(searchCatalogName)
}

print(filteredCatalogNames)

Comments

4

my try...

let brands = ["Apple", "FB", "Google", "Microsoft", "Amazon"]

let b = brands.filter{(x) -> Bool in 
(x.lowercased().range(of: "A".lowercased()) != nil)
}
print(b) //["Apple", "Amazon"]

Comments

3

with help of String extension you can use pure Swift solution (without import Foundation). I didn't check the speed, but it shouldn't be worse as the foundation equivalent.

extension String {
    func contains(string: String)->Bool {
        guard !self.isEmpty else {
            return false
        }
        var s = self.characters.map{ $0 }
        let c = string.characters.map{ $0 }
        repeat {
            if s.startsWith(c){
                return true
            } else {
                s.removeFirst()
            }
        } while s.count > c.count - 1
        return false
    }
}

let arr = ["Hello","Bye","Halo"]
let filtered = arr.filter { $0.contains("lo") }

print(filtered) // ["Hello", "Halo"]

"a".contains("alphabet") // false
"alphabet".contains("")  // true

Comments

2

You also need to compare to NSNotFound. The documentation for rangeOfString:options: says:

An NSRange structure giving the location and length in the receiver of the first occurrence of aString, modulo the options in mask. Returns {NSNotFound, 0} if aString is not found or is empty (@"").

import Foundation

let catalogNames = [ "Hats", "Coats", "Trousers" ]

let matchingTerms = catalogNames.filter {
  $0.rangeOfString(self.txtField.text!, options: .CaseInsensitiveSearch).location != NSNotFound
}

Comments

0

Swift 5:
Considered below example. Filtering (case insensitive) out data from array 1 and populating 2nd array with that

let data = ["Apple", "Oranges", "Banana", "Grapes"]
var filteredData = [String]()

func filterText(_ text: String?) {
    guard let text = text else {return}
    
    filteredData.removeAll()
    for element in data {
        if element.lowercased().starts(with: text.lowercased()){
            filteredData.append(element)
        }
    }
}

Comments

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.