在Swift中过滤一个[AnyObject]数组

28

我在Swift中有一个AnyObject对象数组。每个对象都有餐厅的属性,如名称、类型、位置等。如果我想保留数组中包含类型为“Sushi”的所有对象,应该如何过滤数组?

下面是一个包含2个对象的[AnyObject]样本数组。筛选器应该保留第一个对象(类型: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;
}]

当前代码(但我不确定过滤器是否可以搜索 [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!)

一个问题:我理解你的数组被声明为 [AnyObject],但在你的情况下,可以安全地假设它只包含类型为 Restaurant 的元素吗? - Luca Angeletti
5个回答

56

您的数组objects是一个PFObject对象的数组。因此,要对数组进行过滤,您可以执行以下操作:

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

假设我们正在处理自定义的Restaurant对象,您可以使用filter方法。

假设Restaurant的定义如下:

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

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

假设type是一个字符串数组,你可以这样做:

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

如果您的类型数组可能为nil,则需要对其进行条件解包:
let filteredArray = objects.filter() {
    if let type = ($0 as Restaurant).type as [String]! {
        return contains(type, "Sushi")
    } else {
        return false
    }
}

具体情况会因您对餐厅的声明而略有不同,您并未与我们分享,但希望这可以说明这个想法。


谢谢你的回答。是的,在解析中,type 被设置为字符串。然而,代码出现了错误:使用未声明的类型 'Restaurant' - Onichan
1
好的,日志显示你正在处理自定义对象,但我现在猜测你正在处理一个 PFObject 对象数组。坦白地说,我应该在查看你的 PFQuery 引用时推断出来。无论如何,如果是这种情况,你可以使用类似于我的修订答案的东西。我现在也猜测 Type 属性不是一个字符串数组,而是一个逗号分隔的字符串。 - Rob
1
感谢@Rob提供的修改答案。我尝试了一下,它确实有效!非常感谢。我很长时间都没能弄清楚这个问题。您能否解释一下这两行代码以便澄清一下?if let type = ($0 as PFObject)["Type"] as String { return type.rangeOfString("Sushi") != nil - Onichan
1
@Rachel if let 行 (a) 将数组中的单个对象强制转换为 PFObject 对象;(b) 从该对象获取 Type 属性;并且 (c)可选地将其强制转换为字符串。rangeOfString 用于测试该字符串中是否出现了“Sushi”。 - Rob
我不确定你是否真的需要“全局”的操作,但是,肯定可以更新你的模型以反映你检索到的信息。这并不罕见。 - Rob
显示剩余3条评论

10

Swift 3 解决方案

在数组上使用过滤方法

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

如果类型是数组,则可以使用 return Bool(restaurant.type.contains("sushi")) 返回布尔值。


8

好的,如果数组objects只包含餐厅,则以下代码可以正常工作。

假设餐厅的结构如下:

enum RestaurantType {
    case Sushi, Japanese, Asian
}

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

首先,让我们定义一个餐厅的数组。

var restaurants = objects as [Restaurant]

然后我们可以对其进行过滤:

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

更新: 现在假设objects是一个PFObject数组 请忽略我之前的代码,试试这个:

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

也许它将再次崩溃,问题在于我不知道Restaurant.Type的类型。我正在尝试。也许下一个错误消息会提供更有用的信息。

1
数组 objects 自动从解析查询 var query = PFQuery(className:"Restaurant") 生成。为了使用 restaurants.filter,我需要重构这个数组吗?因为当我在当前的代码中使用它与数组 objects 一起时会出现错误 undeclared type 'Restaurant' - Onichan
我发现了这个线程:http://forums.macrumors.com/showthread.php?t=1315801 我怀疑objects是一个PFObject数组 https://parse.com/docs/ios/api/Classes/PFObject.html 我将更新我的答案。 - Luca Angeletti
1
感谢您的跟进和尝试!你们两个都是对的,对象确实是PFObject。抱歉造成混淆。然而,你的解决方案最后一行出现了错误Type 'AnyObject!' does not conform to protocol 'SequenceType',错误指向了contains这个词。 - Onichan

5

作为Swift 2.0的Rob答案的修改,使用Rob的代码会出现以下错误 -

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

在这里输入图片描述

然而,可以使用守卫语句来解决此问题,如下所示 -

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

1
这个差异看起来有点像Swift 2.0特性所可能带来的个人编码风格。请至少解释一下与@Rob答案的区别,或者考虑编辑Rob的答案并添加Swift 2.0语法的代码示例(同时附上一些解释)。 - try-catch-finally
修改了带有详细信息的注释。 - AppsWise

3
我有一个解决方案如下所示。
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
}

这是过时的逻辑。 - Satyam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接