Swift过滤基于另一个集合的集合

时间:2015-11-19 18:36:50

标签: swift

我有两个班级“Receipe”和“Incredient”。一个recipe可以有一个令人难以置信的列表。现在,我希望当我传递一个令人难以置信的清单时,我应该收到所有收据,其中包含令人难以置信的收据。这就是我所拥有的:

如何根据传入的难以置信的人过滤收据。

class Recipe {

    var name :String!
    var incredients :[Incredient]!

    init(name :String, incredients :[Incredient]) {
        self.name = name
        self.incredients = incredients
    }

}

class Incredient {
    var name :String!

    init(name :String) {
        self.name = name
    }
}

var incredientsToSearchFor = [Incredient(name:"Salt"),Incredient(name :"Sugar")]

var receipe1 = Recipe(name: "Receipe 1", incredients: [Incredient(name: "Salt"),Incredient(name :"Pepper"),Incredient(name :"Water"),Incredient(name :"Sugar")])

var receipe2 = Recipe(name: "Receipe 2", incredients: [Incredient(name: "Salt"),Incredient(name :"Pepper"),Incredient(name :"Water"),Incredient(name :"Sugar")])

var receipe3 = Recipe(name: "Receipe 3", incredients: [Incredient(name :"Pepper"),Incredient(name :"Water"),Incredient(name :"Sugar")])

var receipies = [receipe1,receipe2,receipe3] // list of all the recipies

func getRecipiesByIncrediants(incredients :[Incredient]) -> [Recipe] {

    // WHAT TO DO HERE 

    return nil
}

let matchedRecipies = getRecipiesByIncrediants(incredientsToSearchFor)

1 个答案:

答案 0 :(得分:1)

有些事情需要改变。

首先,这些是数据模型,因此它们应该是struct类型而不是class。这允许您删除初始化程序和选项:

struct Recipe : Equatable {
    let name: String
    let ingredients: [Ingredient]
}

struct Ingredient : Equatable {
    let name : String
}

您会注意到我也制作了Equatable。这样您就可以使用contains在数组中查找它们。没有它,contains不知道这些类型中的两个是否相等。

要符合Equatable,只需添加==方法:

func ==(lhs: Ingredient, rhs: Ingredient) -> Bool {
    return lhs.name == rhs.name
}

func ==(lhs: Recipe, rhs: Recipe) -> Bool {
    return lhs.name == rhs.name && lhs.ingredients == rhs.ingredients
}

创建数据大致相同。我修正了一些拼写错误并将var更改为let,因为这些值不会改变:

let ingredientsToSearchFor = [Ingredient(name:"Salt"), Ingredient(name :"Sugar")]

let recipe1 = Recipe(name: "Recipe 1", ingredients: [Ingredient(name: "Salt"), Ingredient(name :"Pepper"), Ingredient(name :"Water"), Ingredient(name :"Sugar")])

let recipe2 = Recipe(name: "Recipe 2", ingredients: [Ingredient(name: "Salt"), Ingredient(name :"Pepper"), Ingredient(name :"Water"), Ingredient(name :"Sugar")])

let recipe3 = Recipe(name: "Recipe 3", ingredients: [Ingredient(name :"Pepper"), Ingredient(name :"Water"), Ingredient(name :"Sugar")])

let recipes = [recipe1, recipe2, recipe3] // list of all the recipes

现在进行过滤。这是更有效的方法,但为了便于阅读,您可以使用filterreduce

func getRecipesByIngredients(incredients :[Ingredient]) -> [Recipe] {
    return recipes.filter { recipe in
        incredients.reduce(true) { currentValue, ingredient in
            return currentValue && (recipe.ingredients.contains(ingredient))
        }
    }
}

filter返回一个新数组,其中只包含块返回true的元素。 reduce将整个数组合并为一个值(在本例中为truefalse)。因此,我们遍历每个配方,并检查是否所有指定成分都在其中。

调用方法:

let matchedRecipes = getRecipesByIngredients(ingredientsToSearchFor)

这会返回食谱1和2,因为它们都含有盐和糖。

如果您想要含有盐或糖的食谱,请使用reduce(false)并将&&更改为||