28

I have an array of AnyObject objects in Swift. Each object has attributes of a restaurant, such as name, type, loc, etc. How can I filter the array if I want to keep all objects in the array that contain type: "Sushi".

Sample array of [AnyObject] with 2 objects. The filter should keep the first object (type: sushi):

[<Restaurant: 0x7ff302c8a4e0, objectId: LA74J92QDA, localId: (null)> {
    City = "New York";
    Country = "United States";
    Name = Sumo Japan;
    Type = Sushi, Japanese, Asian;
}, <Restaurant: 0x7ff302daa790, objectId: 0aKFrpKN46, localId: (null)> {
    City = "New York";
    Country = "United States";
    Name = Little Italy;
    Type = Italian, Pizza;
}]

Current Code (but I'm not sure if the filter can search through an array of [AnyObject]) :

var query = PFQuery(className:"Restaurant")
query.whereKey("RestaurantLoc", nearGeoPoint:userGeoPoint, withinMiles:50)
query.limit = 2
query.findObjectsInBackgroundWithBlock {
    (objects: [AnyObject]!, error: NSError!) -> Void in
    if objects != nil {
        println("list of objects of nearby")
        println(objects)
        let searchString = "Sushi"
        let predicate = NSPredicate(format: "Type CONTAINS[cd] %@", searchString);

        //Line below gives error: '[AnyObject]' does not have a member named 'filteredArrayUsingPredicate'
        //let filteredArray = objects.filteredArrayUsingPredicate(predicate!)
1
  • One question: I understand your array is declared as [AnyObject], but in your case is it safe to assume it contains only elements of type Restaurant? Commented Dec 30, 2014 at 17:34

5 Answers 5

56

Your array, objects, is an array of PFObject objects. Thus, to filter the array, you might do something like:

let filteredArray = objects.filter() {
    if let type = ($0 as PFObject)["Type"] as String {
        return type.rangeOfString("Sushi") != nil
    } else {
        return false
    }
}

My original answer, based upon an assumption that we were dealing with custom Restaurant objects, is below:


You can use the filter method.

Let's assume Restaurant was defined as follows:

class Restaurant {
    var city: String
    var name: String
    var country: String
    var type: [String]!

    init (city: String, name: String, country: String, type: [String]!) {
        ...
    }
}

So, assuming that type is an array of strings, you'd do something like:

let filteredArray = objects.filter() {contains(($0 as Restaurant).type, "Sushi")}

If your array of types could be nil, you'd do a conditional unwrapping of it:

let filteredArray = objects.filter() {
    if let type = ($0 as Restaurant).type as [String]! {
        return contains(type, "Sushi")
    } else {
        return false
    }
}

The particulars will vary a little depending upon your declaration of Restaurant, which you haven't shared with us, but hopefully this illustrates the idea.

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

8 Comments

Thank you for the answer. Yes, in parse the type is set as string. However, the code gives the error: Use of undeclared type 'Restaurant'
Your code sample showed us what appeared to be a class called Restaurant. Why don't you show us precisely what the definition of that class/struct looks like and we'll be able to make better suggestions. It's hard to write code for a class we don't have. Or step back and embrace the common theme in all of these answers, that you have a Swift array, and if you will probably want to use filter to get the filteredArray. The details will vary based upon your implementation.
OK, the log suggested you were dealing with custom objects, but I'm now guessing you're dealing with an array of PFObject objects. Frankly, I should have inferred that looking at your PFQuery reference. Anyway, if that's the case, you might use something like my revised answer. I'm also now guessing that the Type property is not an array of strings, but a comma delimited string.
Thank you @Rob for the revised answer. I tried it, and it works! Thank you so much. I could not figure this out for a long time. Is it possible for you to explain the two lines just for clarification? if let type = ($0 as PFObject)["Type"] as String { return type.rangeOfString("Sushi") != nil
@Rachel The if let line (a) casts the individual objects in the array to be PFObject objects; (b) gets the Type property from that object; and (c) optionally casts that to a string. The rangeOfString tests to see if "Sushi" appears anywhere in that string.
|
10

Swift 3 Solution

Use the filter method on an array.

let restaurants: [Restaurants] = [...]
restaurants.filter({(restaurant) in
    return Bool(restaurant.type == "sushi")
})

or return Bool(restaurant.type.contains("sushi")) if type is an array.

Comments

8

Ok, if the array objects contains only Restaurant(s) the following code does work.

Lets say Restaurant is something like this:

enum RestaurantType {
    case Sushi, Japanese, Asian
}

class Restaurant {
    var type = [RestaurantType]()
    // more properties here...
}

First of all lets define an array of Restaurant(s).

var restaurants = objects as [Restaurant]

Then we can filter it:

var sushiRestaurants = restaurants.filter { (restaurant : Restaurant) -> Bool in
    return contains(restaurant.type, .Sushi)
}

Update: Now I am assuming objects is an array of PFObject(s) Just ignore my previous code and try this:

var restaurants = objects as [PFObject]
var sushiRestaurants = restaurants.filter { (restaurant : PFObject) -> Bool in
    return contains(restaurant["Type"], "Sushi")
}

Maybe it will crash again, the problem is that I don't know the type of Restaurant.Type. I'm trying. Maybe the next error message will provide more useful info.

3 Comments

The array: objects is automatically generated from the parse query var query = PFQuery(className:"Restaurant") In order to use the restaurants.filter, do I need to reconstruct the array? Because the current code gives the error undeclared type 'Restaurant' when I use it with the array objects
I found this thread: forums.macrumors.com/showthread.php?t=1315801 I suspect objects is an array of PFObject parse.com/docs/ios/api/Classes/PFObject.html I am going to update my answer.
Thank you for the follow up and for trying! You are both right, that the objects is indeed PFObject. Sorry for the confusion. However, the last line your solution gives this error Type 'AnyObject!' does not conform to protocol 'SequenceType' the error points at the word contains
5

Modification of Rob's answer as Swift 2.0, In swift 2.0 using Rob's code gives error as follows -

initializer for conditional binding must have optional type, not 'string'

enter image description here

However it can be solved by using guard statement instead of if-let as below -

let filteredArray = objects.filter() {
            guard let type = ($0 as PFObject)["Type"] as String else {
                return false
            } 
            return type.rangeOfString("Sushi") != nil
        }

2 Comments

The difference looks a bit like personal coding style possible by Swift 2.0 features. Please at least explain the difference to @Rob's answer or consider editing Rob's answer adding the Swift 2.0 syntaxed code example (also with some explanation).
Modified the comment with details.
3

I have a solution as given below.

func filterByCuisineType(list: [Restaurant]) -> [Restaurant]{

    if self.cuisineTypes.count == 0 {
        return list
    }

    let array: [Restaurant] =  list.filter { (restaurant) -> Bool in

        for cuisineName in self.cuisineTypes{

            let isContained: Bool = restaurant.cuisineType.contains(cuisineName)

            if isContained {
                return true
            }
        }

        return false
    }

    return array
}

1 Comment

This is outdated logic

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.