5

Wondering if someone could help me out with filtering using predicates in Swift.

I have a somewhat messy datasource that I am using to populate a UITableView. The data source is an array of structures. The struct is defined as follows:

struct Exercises {
    let category: String
    let name : String
    let x_seed: [Double]
    let y_seed: [Double]
    let hasMult: Bool
}

Now in my tableview controller I'm holding an array of structures that contains all of the data for the table.

class MainTableViewController: UITableViewController, UISearchResultsUpdating {


var exercises = [Exercises]()
var filtered_exercises = [Exercises]()
var resultSearchController = UISearchController()

override func viewDidLoad() {
    super.viewDidLoad()

    // MARK: - Table view data source
    self.exercises = [
        Exercises(category:"Sports", name:"Bowling", x_seed:[125,155,185], y_seed:[3.00, 3.73, 4.43], hasMult:false),
        Exercises(category:"Sports", name:"Water Polo", x_seed:[125,155,185], y_seed:[10.00, 12.40,14.80], hasMult:false),
        Exercises(category:"Sports", name:"Handball", x_seed:[125,155,185], y_seed:[12.00, 14.87, 17.77], hasMult:false),
        Exercises(category:"Sports", name:"Dancing", x_seed:[125,155,185], y_seed:[3.00, 3.73, 4.43], hasMult:true),
        Exercises(category:"Sports", name:"Frisbee", x_seed:[125,155,185], y_seed:[3.00, 3.73, 4.43], hasMult:false),
        Exercises(category:"Sports", name:"Volleyball", x_seed:[125,155,185], y_seed:[3.00, 3.73, 4.43], hasMult:false),
        Exercises(category:"Sports", name:"Archery", x_seed:[125,155,185], y_seed:[3.50, 4.33, 5.17], hasMult:false),
        Exercises(category:"Sports", name:"Golf", x_seed:[125,155,185], y_seed:[3.50, 4.33, 5.17], hasMult:true)]

    self.resultSearchController = ({
        let controller = UISearchController(searchResultsController: nil)
        controller.searchResultsUpdater = self
        controller.dimsBackgroundDuringPresentation = false
        controller.searchBar.sizeToFit()

        self.tableView.tableHeaderView = controller.searchBar

        return controller
    })()

    self.tableView.reloadData()
}

What I would like to do is filter the exercises array based on the 'name' field and populate a new datasource filtered_exercises to fill the tableview. I am not sure how to wrap my head around how to use predicates in this situation.

// Search functionality 
func updateSearchResultsForSearchController(searchController: UISearchController)
{
    filtered_exercises.removeAll(keepCapacity: false)

    let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %@", searchController.searchBar.text!)
    // ??????????????

    self.tableView.reloadData()
}

I know I could read all of the names in a string array and display that in the tableview easily. The problem is that I need to preserve the structures as the data contained there is passed onto other view controllers.

So, How can I filter an array of structs?

Thanks!

1 Answer 1

3

If you do not insist on NSPredicate (don't see a reason why you should since you're not using NSFetchRequest, ...), here's the code:

struct Exercises {
  let category: String
  let name : String
  let x_seed: [Double]
  let y_seed: [Double]
  let hasMult: Bool
}

let exercises = [
  Exercises(category:"Sports", name:"Bowling", x_seed:[125,155,185], y_seed:[3.00, 3.73, 4.43], hasMult:false),
  Exercises(category:"Sports", name:"Water Polo", x_seed:[125,155,185], y_seed:[10.00, 12.40,14.80], hasMult:false),
  Exercises(category:"Sports", name:"Handball", x_seed:[125,155,185], y_seed:[12.00, 14.87, 17.77], hasMult:false),
  Exercises(category:"Sports", name:"Dancing", x_seed:[125,155,185], y_seed:[3.00, 3.73, 4.43], hasMult:true),
  Exercises(category:"Sports", name:"Frisbee", x_seed:[125,155,185], y_seed:[3.00, 3.73, 4.43], hasMult:false),
  Exercises(category:"Sports", name:"Volleyball", x_seed:[125,155,185], y_seed:[3.00, 3.73, 4.43], hasMult:false),
  Exercises(category:"Sports", name:"Archery", x_seed:[125,155,185], y_seed:[3.50, 4.33, 5.17], hasMult:false),
  Exercises(category:"Sports", name:"Golf", x_seed:[125,155,185], y_seed:[3.50, 4.33, 5.17], hasMult:true)
]

let options = NSStringCompareOptions.CaseInsensitiveSearch | NSStringCompareOptions.DiacriticInsensitiveSearch

// Filter exercises by name (case and diacritic insensitive)
let filteredExercises = exercises.filter {
  $0.name.rangeOfString("Ol", options: options) != nil
}

let filteredExerciseNames = ", ".join(filteredExercises.map({ $0.name }))
println(filteredExerciseNames)

It prints Water Polo, Volleyball, Golf.

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

3 Comments

This is a good start. However it only returns an array of strings for names. Ideally, I would be able to filter the struct array by names and return a struct array of filtered results. Is that possible? If not I probably can make this work. Thanks!
It's there, check filteredEcercises array, it's [Exercise] array :) filteredEcercisesNames is just for demonstration that it works.
Oh duh... I don't know how I missed that. Well thanks, this works perfectly! Cheers.

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.