5

I need some help filtering an array of Structs.

This is what I am doing currently, it filters the array but not correctly. For example lets say I search for an item in the array with "Mid" I have one item that should be shown however the item shown starts with "Bad".

    var array = breweries.filter() { $0.name?.lowercaseString.rangeOfString(searchController.searchBar.text.lowercaseString) != nil }

    results = array

here is my Struct

struct Breweries {
    let name: String?
    let breweryId: String?
    let distance: Double?
    let largeIconURL: String?
    let streetAddress: String?
    let locality: String?
    let region: String?
    let phone: String?
    let website: String?

    init(brewDictionary: [String: AnyObject]) {

        name = brewDictionary["brewery"]?["name"] as? String
        breweryId = brewDictionary["breweryId"] as? String
        distance = brewDictionary["distance"] as? Double
        largeIconURL = brewDictionary["brewery"]?["images"]??.objectForKey("large") as? String
        streetAddress = brewDictionary["streetAddress"] as? String
        locality = brewDictionary["locality"] as? String
        region = brewDictionary["region"] as? String
        phone = brewDictionary["phone"] as? String
        website = brewDictionary["website"] as? String


    }
}

Please point in the right direction!

Note: I am using Swift 1.2

Update:

I thought a video would be of help to better explain what I am trying to do.

Demo Of issue

What I want is to find the filter the array so only the item with a similar name is shown.

Update 2: As it turns out I forgot to handle the case when my UISearchController was active.

MillerApps
  • 152
  • 1
  • 13
  • I wrote an answer to you, but to really answer it, you need to provide what is your actual problem (or maybe input data, and desired output would give clear idea about it). – Jiri Trecak Jul 22 '15 at 19:44
  • possible duplicate of [How do I check if a string contains another string in Swift?](http://stackoverflow.com/questions/24034043/how-do-i-check-if-a-string-contains-another-string-in-swift) – Aaron Brager Jul 22 '15 at 20:02

3 Answers3

5

Assuming your Struct name is Breweries and it has a name property, try this:

let array = breweries.filter() {
    ($0.name!.lowercaseString as NSString).containsString(searchController.searchBar.text.lowercaseString)
}
Jorge
  • 1,066
  • 8
  • 16
2

Your usage of filter is correct, but your closure seem to be complicated with no clear goal. I suggest you to write an extension (or possibly use what I am using):

extension String {

    func contains(search: String, ignoreCase: Bool = false, ignoreDiacritic: Bool = false) -> Bool {

        var options = NSStringCompareOptions.allZeros

        if ignoreCase { options |= NSStringCompareOptions.CaseInsensitiveSearch }
        if ignoreDiacritic { options |= NSStringCompareOptions.DiacriticInsensitiveSearch }

        return self.rangeOfString(search, options: options) != nil
     }
}

This way you can use closure like this to search:

breweries.filter() { 
    $0.name?.contains("x") // Precise search
    $0.name?.contains("x", ignoreCase: true, ignoreDiacritics: true) // Ignores diacritics and lower / upper case
}

of course, you can use | or & to search for multiple parameters

breweries.filter() { 
    $0.name?.contains("x") || $0.streetAddress?.contains("x")
}

Hope it helps!

Jiri Trecak
  • 5,092
  • 26
  • 37
0

Here is an example from an investing app with struct:

import Foundation

public struct SNStock {

  public let ticker:NSString
  public let name:NSString

  init(ticker:NSString, name:NSString) {
    self.ticker = ticker
    self.name = name
  }
}

Search on Main Thread:

public func searchStocksByKeyword(keyword:String) -> [SNStock] {
  let lowercaseKeyword = keyword.lowercaseString
  var searchResults:[SNStock] = []
  searchResults = stocks.filter({ (stock:SNStock) -> Bool in
    return stock.ticker.lowercaseString.hasPrefix(lowercaseKeyword)
  })
  if (searchResults.count == 0) {
    searchResults = stocks.filter({ (stock:SNStock) -> Bool in
      return stock.name.lowercaseString.hasPrefix(lowercaseKeyword)
    })
  }
  searchResults.sortInPlace {
    ($0.ticker as String) < ($1.ticker as String)
  }
  return searchResults;
}

Search on Background Thread:

public func searchStocksByKeyword(keyword:String, completion:(stocks:[SNStock])->()) {
  let qualityOfServiceClass = QOS_CLASS_USER_INTERACTIVE
  let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
  dispatch_async(backgroundQueue, {
    let stocks:[SNStock] = self.searchStocksByKeyword(keyword)
    dispatch_async(dispatch_get_main_queue(), { () -> Void in
      completion(stocks: stocks)
    })
  })
}
Zorayr
  • 23,770
  • 8
  • 136
  • 129