27

I have an array containing a number of strings. I have used contains() (see below) to check if a certain string exists in the array however I would like to check if part of a string is in the array?

itemsArray = ["Google, Goodbye, Go, Hello"]

searchToSearch = "go"

if contains(itemsArray, stringToSearch) {
    NSLog("Term Exists")
}
else {
    NSLog("Can't find term")
}

The above code simply checks if a value is present within the array in its entirety however I would like to find "Google, Google and Go"

Daniel Bramhall
  • 1,451
  • 4
  • 18
  • 24

9 Answers9

31

Try like this.

let itemsArray = ["Google", "Goodbye", "Go", "Hello"]
let searchToSearch = "go"

let filteredStrings = itemsArray.filter({(item: String) -> Bool in

     var stringMatch = item.lowercaseString.rangeOfString(searchToSearch.lowercaseString)
     return stringMatch != nil ? true : false
})

filteredStrings will contain the list of strings having matched sub strings.

In Swift Array struct provides filter method, which will filter a provided array based on filtering text criteria.

Amit89
  • 3,000
  • 1
  • 19
  • 27
  • Thanks for that. How would I explicitly check if the array had anything in it as a result of the search? – Daniel Bramhall Jun 16 '15 at 15:55
  • If i understand your question correctly, you can use count to check wether anything there in the result array filteredStrings. Use this - filteredStrings.count – Amit89 Jun 17 '15 at 06:10
  • 2
    In Swift 4.0 rangeOfString is changed to range(of: "string") and lowercaseString is changed to lowerCased() – Hammad Tariq Jun 14 '18 at 17:11
  • I have problem with filter time using this solution. I have an array of Type [Articles] with 1000+ elements and I have to search in description of that article and the description of each article is 1500+ words. filtering is taking too much time. Around 2-3 seconds. – Shahbaz Saleem Jan 04 '19 at 07:45
31

First of all, you have defined an array with a single string. What you probably want is

let itemsArray = ["Google", "Goodbye", "Go", "Hello"]

Then you can use contains(array, predicate) and rangeOfString() – optionally with .CaseInsensitiveSearch – to check each string in the array if it contains the search string:

let itemExists = contains(itemsArray) {
    $0.rangeOfString(searchToSearch, options: .CaseInsensitiveSearch) !=  nil
}

println(itemExists) // true 

Or, if you want an array with the matching items instead of a yes/no result:

let matchingTerms = filter(itemsArray) {
    $0.rangeOfString(searchToSearch, options: .CaseInsensitiveSearch) !=  nil
}

println(matchingTerms) // [Google, Goodbye, Go]

Update for Swift 3:

let itemExists = itemsArray.contains(where: {
    $0.range(of: searchToSearch, options: .caseInsensitive) != nil
})
print(itemExists)

let matchingTerms = itemsArray.filter({
    $0.range(of: searchToSearch, options: .caseInsensitive) != nil
})
print(matchingTerms)
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • why does the `contains` have a `throw`? Isn't it either true or false? – mfaani Aug 22 '17 at 13:19
  • 1
    @Honey: You can pass a throwing closure to the contains() method. If the closure throws an error then it is rethrown by contains(). – Compare https://stackoverflow.com/questions/43305051/what-are-the-differences-between-throws-and-rethrows-in-swift. – Martin R Aug 22 '17 at 13:22
15

Try like this.

Swift 3.0

import UIKit

let itemsArray = ["Google", "Goodbye", "Go", "Hello"]

var filterdItemsArray = [String]()


func filterContentForSearchText(searchText: String) {
    filterdItemsArray = itemsArray.filter { item in
        return item.lowercased().contains(searchText.lowercased())
    }
}

filterContentForSearchText(searchText: "Go")
print(filterdItemsArray)

Output

["Google", "Goodbye", "Go"]
Ashok R
  • 19,892
  • 8
  • 68
  • 68
  • 1
    Please do not post the [same answer](http://stackoverflow.com/a/40399381/2227743) multiple times. If a question already has an existing answer elsewhere, then *flag the question as duplicate* instead of answering again. Thanks. – Eric Aya Nov 03 '16 at 11:07
10

In Swift 5 with better readability :

let itemsArray = ["Google", "Goodbye", "Go", "Hello"]
let searchString = "Googled"

let result = itemsArray.contains(where: searchString.contains)
print(result) //prints true in the above case.
AnupamChugh
  • 1,779
  • 1
  • 25
  • 36
  • this does the reverse search - which item in the itemsArray is a substring of the searchString. Nice use of syntax but this will not satisfy the original question, where the searchString should be a substring of one of the items. – mitrenegade Jul 14 '22 at 20:34
5

MARK:- Swift 5, Swift 4

//MARK:- You will find the array when its filter in "filteredStrings" variable you can check it by count if count > 0 its means you have find the results

let itemsArray = ["Google", "Goodbye", "Go", "Hello"]
let searchToSearch = "go"

let filteredStrings = itemsArray.filter({(item: String) -> Bool in

    let stringMatch = item.lowercased().range(of: searchToSearch.lowercased())
    return stringMatch != nil ? true : false
})
print(filteredStrings)


if (filteredStrings as NSArray).count > 0
{
    //Record found
    //MARK:- You can also print the result and can do any kind of work with them
}
else
{
    //Record Not found
}
Shakeel Ahmed
  • 5,361
  • 1
  • 43
  • 34
1
func filterContentForSearchText(_ searchText: String) {
   filteredString = itemsArray.filter({( item : String) -> Bool in
            return  item.lowercased().contains(searchText.lowercased())
    })
}
Jasica Peter
  • 91
  • 10
0

In Swift 4:

    let itemsArray = ["Google", "Goodbye", "Go", "Hello"]
    let searchString = "Go"
    let filterArray = itemsArray.filter({ { $0.range(of: searchString, options: .caseInsensitive) != nil}
    })
    print(filterArray)
Community
  • 1
  • 1
BIJU C
  • 21
  • 5
0

I had the same problem recently, didn't like most of these answers, solved it like this:

let keywords = ["doctor", "hospital"] //your array

func keywordsContain(text: String) -> Bool { // text: your search text
    return keywords.contains { (key) -> Bool in
        key.lowercased().contains(text.lowercased())
    }
}

This will also correctly trigger searches like "doc", which many of the above answers do not and is best practice. contains() is more performant than first() != nil source: https://www.avanderlee.com/swift/performance-collections/

Alex M
  • 11
  • 2
-1

Swift 5

let itemExist = itemsArray.contains {
    $0.range(of: stringToSearch) != nil
}
AnderCover
  • 2,488
  • 3
  • 23
  • 42