多重过滤的布尔语句 Swift

Boolean statement for multiple filtering Swift

我目前正在 Swift 4.2 中创建一个应用程序,我想要一个允许用户 select 多个过滤器的过滤功能。

我有一组当前 selected 过滤器,例如 ["Low"、"Unread"]。我还有一个要过滤的 object 数组。但我正在努力弄清楚如何将多个过滤器应用于此数组,特别是由于 object 具有 children,而后者又具有过滤的属性。例如 object 数组包含 bulletin.importance.name,这是 属性 将检查 "Low"。

以下代码是一个布尔返回函数,它将获取要在公告数组 objects:

上使用的过滤器
return (bulletin.bulletinVersion?.issued == true) && (scopes.contains("All") || (scopes.contains((bulletin.bulletinVersion?.bulletin?.importance?.name)!) ||
        (!scopes.contains(where: {[=11=] == "Low" || [=11=] == "Normal" || [=11=] == "High"}))) && (scopes.contains(bulletin.read(i: bulletin.firstReadDate)) ||
            (!scopes.contains(where: {[=11=] == "Unread"}))) &&
            (scopes.contains(bulletin.signed(i: bulletin.signDate)) && bulletin.bulletinVersion?.bulletin?.requiresSignature == true) && scopes.contains(bulletin.favourited(i: bulletin.favourite)))

这是我目前尝试的布尔检查。我希望它很难设置,所以如果用户 selects "High" 和 "Unread" 它只会显示匹配这两个过滤器的 objects。

此处调用该函数,获取过滤器并过滤所有公告的数组,这些公告应根据过滤器显示在其中:

currentBulletinArray = bulletinArray.filter({bulletin -> Bool in
    let doesCategoryMatch = getScopeFilters(issued: true, scopes: scope, bulletin: bulletin, signature: true)

    if searchBarIsEmpty(){
        return doesCategoryMatch
    } else {
        return doesCategoryMatch && (bulletin.bulletinVersion?.bulletin?.name?.lowercased().contains(searchText.lowercased()))!
    }
   })

我希望能够设置任何过滤器组合,其中返回的 .filter 谓词将仅显示与所有过滤器匹配的公告。 因此,未读 + 未签名 + 高将显示所有未读和未签名的高重要性公告。

我不确定你在问什么,但你可以。首先,您可以格式化您的代码以使其更具可读性......我知道多个 return 点被认为是不好的,但潮流似乎正在转向这一点。我会按照重要性的顺序挑选案例,return 你能找到的任何明确的布尔值。例如(未经测试的代码,因为我不知道公告和范围是什么):

func foo(bulletin: Bulletin, scopes: Scopes) -> Bool {
    if bulletin.bulletinVersion?.issued == true && scopes.contains("All") {
        return true
    }
    if scopes.contains(bulletin.bulletinVersion?.bulletin?.importance?.name)! {
        return true
    }
    if scopes.contains(bulletin.bulletinVersion?.bulletin?.importance?.name)! {
        return true
    }
    if !scopes.contains(where: {[=10=] == "Low" || [=10=] == "Normal" || [=10=] == "High"})
        && (scopes.contains(bulletin.read(i: bulletin.firstReadDate) {
        return true
    }

    if !scopes.contains(where: {[=10=] == "Unread"}) 
        && scopes.contains(bulletin.signed(i: bulletin.signDate)
        && bulletin.bulletinVersion?.bulletin?.requiresSignature == true
        && scopes.contains(bulletin.favourited(i: bulletin.favourite)) {
        return true
    }
    return false
}

请注意,这些子句中的每一个都会测试是否为真,如果合适的话 returns 它,因此一旦找到真实情况,函数就会 returns 。 tsts 的顺序可能会影响逻辑。

我会考虑创建一个带有公告、范围和return真或假的方法的协议。

protocol Filter {
    func test(bulletin: Bulletin, scopes: Scopes) -> Bool
}

然后创建此协议的实现者:

class AFilter: Filter {
    func test(bulletin: Bulletin, scopes: Scopes) -> Bool {
        if bulletin.bulletinVersion?.issued == true && scopes.contains("All") {
            return true
        }
        return false
    }
}

一旦你建立了你可以做的过滤器实例列表(修改以匹配明确的要求):

for filter in filters {
    if !filter.test(bulletin: bulletin, scopes: scopes) {
        return false
    }
}
return true

(奖励:请注意使用此设计模式更改逻辑是多么容易)

我决定将每个过滤器放入字典中,而不是尝试将大量布尔组合放入一个语句中:

 public var filters:[String: Any] = ["importance":[],
                             "unread": false,
                             "unsigned": false,
                             "favourite": false]

重要性过滤器将包含一个字符串数组,例如 ["Low"、"Medium"、"High"]。

单击过滤器按钮时,如果过滤器是布尔值或数组中的 appended/removed,过滤器将被切换:

if(!importanceToAdd.isEmpty){
            filters["importance"] = importanceToAdd
        }
        if(cell.filterTitleLabel.text == "Unread")
        {
            filters["unread"] = true
        }
        if(cell.filterTitleLabel.text == "Unsigned")
        {
            filters["unsigned"] = true
        }
        if(cell.filterTitleLabel.text == "Favourites")
        {
            filters["favourite"] = true
        }

然后,在一个单独的函数中,我检查过滤器是否已独立设置。如果是,则按以下每个条件过滤公告数组:

 if let importance = filters["importance"] as! [String]?{
        if(importance.count != 0){
            filteredBulletins = filteredBulletins.filter({importance.contains(([=12=].bulletinVersion?.bulletin?.importance?.name)!)})
        }
    }

    if let unread = filters["unread"] as! Bool?
    {
        if(unread)
        {
            filteredBulletins = filteredBulletins.filter({[=12=].firstReadDate == nil})
        }

    }

    if let unsigned = filters["unsigned"] as! Bool?
    {
        if(unsigned)
        {
            filteredBulletins = filteredBulletins.filter({[=12=].bulletinVersion?.bulletin?.requiresSignature == true && [=12=].signDate == nil})
        }
    }

    if let favourite = filters["favourite"] as! Bool?
    {
        if(favourite)
        {
            filteredBulletins = filteredBulletins.filter({[=12=].favourite == true})
        }
    }

字典中包含和删除过滤器确实使我的需求更加明确。试图创建一个布尔语句的怪物将是无限困难的,以使其足够动态以匹配每个可能的过滤器组合(我什至不确定它是否可能)。

但是感谢所有评论提供替代解决方案的人,你们真的帮助我跳出框框思考! :)