如何在Swift中使用可选的多个条件过滤数组?

时间:2019-02-08 18:33:01

标签: arrays swift filter optional

我有几个条件可以用来过滤数组。这些条件是可选的,并存储在struct中,因为用户只能选择其中的一部分。我有一系列模型。我尝试使用过滤器方法,但是您必须为其提供非可选条件。应该采用什么方法摆脱可选参数,并将该标准添加到过滤方法中?

带有过滤选项的过滤结构

struct Filter {
  var brand: String?
  var price: Int?
  var consuption: Int?
}

模型类

class CarOffer {
  var brand: String
  var price: Int
  var color: String
  var consumption: Int
}

这是我尝试做的,但是没有运气,因为filter.price是可选的,我不知道它是否会是。我了解我必须删除一个可选项,但是如何根据其可选性在过滤器方法中添加过滤条件?还是我选择了错误的方法?

let offers: [CarOffer] = […]

func applyFilter(filter: Filter) -> [CarOffer] {

let filteredOffers = offers.filter { $0.brand == filter.brand && $0.price <= filter.price && $0.consumption <= filter.consumption }

return filteredOffers
}

3 个答案:

答案 0 :(得分:2)

通过将代码简化和分解成较小的部分,您会更轻松。没有理由为什么在某些条件下过滤数组的函数也必须负责确定元素是否满足这些条件。您在思维上陷入了陷阱,以为过滤谓词在闭合中是&&条件的一长链。

struct CarOffer {
    let brand: String
    let price: Int
    let color: String
    let consumption: Int
}

struct CarFilter {
    let brand: String?
    let price: Int?
    let consumption: Int?

    func matches(car: CarOffer) -> Bool {
        if let brand = self.brand, brand != car.brand { return false }
        if let price = self.price, price != car.price { return false }
        if let consumption = self.consumption, consumption != car.consumption { return false }
        return true
    }
}

extension Sequence where Element == CarOffer {
    func filter(carFilter: CarFilter) -> [CarOffer] {
        return self.filter(carFilter.matches)
    }
}

let filter = CarFilter(brand: nil, price: nil, consumption: nil)
let offers: [CarOffer] = [] //...
let filteredOffers = offers.filter(carFilter: filter)

答案 1 :(得分:0)

您可以简单地使用默认值代替filter的可选值。如果您使用offer的默认值,则filter会在可选属性为nil的情况下简单地返回true。

func applyFilter(filter: Filter) -> [CarOffer] {

    let filteredOffers = offers.filter { $0.brand == filter.brand && $0.price <= (filter.price ?? $0.price) && $0.consumption <= (filter.consumption ?? $0.consumption) }

    return filteredOffers
}

答案 2 :(得分:0)

您可以将过滤器转换为闭包,并添加一个初始值设定项,以便轻松通过我们不关心的过滤器:

struct Filter {
    var brand: (String) -> Bool
    var price: (Int) -> Bool
    var consuption: (Int) -> Bool

    init(brand: @escaping (String) -> Bool = { _ in return true },
         price: @escaping (Int) -> Bool = { _ in  return true },
         consuption: @escaping (Int) -> Bool = { _ in  return true }) {
        self.brand = brand
        self.price = price
        self.consuption = consuption
    }
}

这提供了最大的灵活性,因为从那时起您可以添加所需的任何类型的过滤。就像根据原始结构添加文件管理器一样,忽略字段的可选选项:

init(brand: String? = nil,
     price: Int?  = nil,
     consuption: Int? = nil) {
    self.brand = { brand == nil || brand == $0 }
    self.price = { price == nil || price! <= $0 }
    self.consuption = { consuption == nil || consuption! <= $0 }
}