Как отфильтровать массив в Swift с несколькими дополнительными критериями? - PullRequest
0 голосов
/ 08 февраля 2019

У меня есть несколько критериев для фильтрации массива.Эти критерии являются дополнительными и хранятся в структуре, поскольку пользователь может выбрать только часть из них.У меня есть множество моделей.Я пытался использовать метод фильтра, но вы должны предоставить необязательные критерии для него.Какой подход должен быть, чтобы избавиться от опций и добавить эти критерии к методу фильтрации?

Структура фильтра с параметрами фильтрации

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 голосов
/ 08 февраля 2019

Вам было бы легче, если бы вы упростили и разбили ваш код на более мелкие части.Нет причины, по которой функция, которая фильтрует массив по некоторым условиям, также должна отвечать за выяснение, соответствует ли элемент этим условиям.Вы мысленно оказались в ловушке, думая, что предикат фильтра должен быть одной длинной цепочкой && условий в замыкании.

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)
0 голосов
/ 08 февраля 2019

Вы можете преобразовать фильтры в замыкания и добавить инициализатор, который позволяет легко проходить фильтры, которые нам не нужны:

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 }
}
0 голосов
/ 08 февраля 2019

Вы можете просто использовать значение по умолчанию вместо filter s Необязательные значения.Если вы используете значение по умолчанию offer, filter просто вернет true, если дополнительные свойства были nil.

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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...