1

I have an array of AnyObject objects in Swift (eventually, this array will be populated by querying a Parse database). Each object in the array has attributes of a publication, such as fullTitle, url, and journal. How can I filter the array to select all objects that match the search string for any value (e.g. where the fullTitle, url, or journal include "Forbes")?

Below is example code from a playground. First the sample array:

var publication1 = [
    "fullTitle": "My first blog",
    "url": "www.forbes.com/post1",
    "journal": "Forbes
]

var publication2 = [
    "fullTitle": "My second blog",
    "url": "www.wsj.com/post1",
    "journal": "Wall Street Journal"
]

var publications: [AnyObject] = [publication1, publication2]

Then, the filter function:

func filterContentForSearchText(searchText: String) {
    let filteredPublications = publications.filter() {
        if let fullTitle = ($0)["fullTitle"] as? String {
            return fullTitle.rangeOfString(searchText) != nil
        } else {
            return false
        }
    }
}

Now, if I call the function with "first" as an argument, it should return the first object out of the array:

println(filterContentForSearchText("first"))

However, this command gives no result. How can I fix this? Also, how can I query all fields of the object for the searchText, not just the fullTitle field?

Thank you.

3 Answers 3

1

Here's a simple example that returns an array of matches in all fields:

func filterContentForSearchTextInAllFields(searchText: String) -> [String] {
    var results = [String]()
    for publication in publications {
        for (key, value) in publication {
            if (value as NSString).containsString(searchText) {
                results.append(value)
            }
        }
    }
    return results
}

println(filterContentForSearchTextInAllFields("blog"))

This one only works on titles:

func filterContentForSearchText(searchText: String) -> [String] {
    var results = [String]()
    for publication in publications {
        if let fullTitle = publication["fullTitle"] {
            if (fullTitle as NSString).containsString(searchText) {
                results.append(fullTitle)
            }
        }
    }
    return results
}

println(filterContentForSearchText("first"))

UPDATE

Here's a version for what you've asked in the comments:

func filterContentForSearchText(searchText: String) -> [[String:String]] {
    var results = [[String:String]]()
    for publication in publications {
        if let fullTitle = publication["fullTitle"] as? String {
            if (fullTitle as NSString).containsString(searchText) {
                results.append(publication as! [String : String])
            }
        }
    }
    return results
}

println(filterContentForSearchText("first"))

Your "rows" are dictionaries: in the loop we assign each one to the "publication" variable, so we just take the one whose title matches the search terms then append it to an array of dictionaries.

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

5 Comments

Thanks, this works! What it returns is an array of strings. I'd like to select the entire "rows" of the database for which the searchText matches the fullTitle, not just the fullTitle string, so that I can later use other values such as the url and journal for that row. How would you do that?
This worked fabulously! I had to change my var filteredPublications to an array of AnyObject, the output of the function to an array of AnyObjects, and take out the publication in the append line as a dictionary of strings.
A (final?) question: let's say I type the first three letters of "Forbes", i.e. f, o, r. In this code, each time I enter a character, all matching publications are appended to filteredPublications. This means that all entries with Forbes will be added three times. What I want to happen is that each time I enter an additional character into the searchBar, the filteredPublications var is cleared, and only the publications that match all characters in the searchBar are appended. How'd you do that? Thanks for your help, this is very helpful!
I fixed it already, by adding: filteredPublications.removeAll(keepCapacity: false)
@TitiaanPalazzi Where did you add removeAll(keepCapacity: false)?
0

Here is the route I went. Instead of an array of AnyObject I just let Swift infer the type

var publications = [publication1, publication2]

func searchPublications(seachText: String) -> [[String: String]] {
   let filteredPublications = publications.filter { $0
       for (_, value) in $0 {
           if let found = value.rangeOfString(seachText, options: NSStringCompareOptions.CaseInsensitiveSearch, range: Range<String.Index>(start: value.startIndex, end: value.endIndex), locale: NSLocale.currentLocale()) {
               return true
           }
       }

       return false
   }

   return filteredPublications
}

2 Comments

Aahrens, this doesn't work for me: "Type 'AnyObject' does not conform to protocol 'SequenceType'."
That's because you're declaring that your array of publications could be anything. Notice how I let it infer the type by being an array of publications . Which is just an array of dictionaries.
0
    Swift 3.0
    This is worked for me.
    I want filter data by it's status 0 or 1. 

    var arrRooms:[[String:AnyObject]] = [
        [
            "id": 30 as AnyObject,
            "name": "Earth" as AnyObject,
            "status": 0 as AnyObject,
            "duration": 10 as AnyObject
        ],
        [
            "id": 27 as AnyObject,
            "name": "Mars" as AnyObject,
            "status": 1 as AnyObject,
            "duration": 0 as AnyObject
        ]
    ]

    let StatusPredicate = NSPredicate(format: "status = 1 ")

    let arrFilter:[[String:AnyObject]] = (arrRooms as NSArray).filtered(using: StatusPredicate) as! [[String : AnyObject]]

    print(arrFilter);
    // output [["name": Mars, "status": 1, "id": 27, "duration": 0]]

it may be useful.thanks

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.