用于多次过滤的布尔语句Swift

时间:2018-10-16 13:12:02

标签: ios swift filter boolean predicate

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

我有一个当前选择的过滤器数组,例如[“ Low”,“ Unread”]。我也有一个被过滤对象的数组。但是我正在努力弄清楚如何将多个过滤器应用于此数组,特别是由于对象具有子对象,而子对象又具有针对其进行过滤的属性。例如,对象数组包含bulletin.importance.name,这是将被检查为“低”的属性。

以下代码是一个布尔返回函数,它将获取要在公告对象数组上使用的过滤器:

private HashMap<String, User> dict = new HashMap<String, User>();

这是我当前对布尔检查的尝试。我希望对它进行硬设置,以便如果用户选择“高”和“未读”,它将仅显示与这两个过滤器都匹配的对象。

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

return (bulletin.bulletinVersion?.issued == true) && (scopes.contains("All") || (scopes.contains((bulletin.bulletinVersion?.bulletin?.importance?.name)!) ||
        (!scopes.contains(where: {$0 == "Low" || $0 == "Normal" || $0 == "High"}))) && (scopes.contains(bulletin.read(i: bulletin.firstReadDate)) ||
            (!scopes.contains(where: {$0 == "Unread"}))) &&
            (scopes.contains(bulletin.signed(i: bulletin.signDate)) && bulletin.bulletinVersion?.bulletin?.requiresSignature == true) && scopes.contains(bulletin.favourited(i: bulletin.favourite)))

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

2 个答案:

答案 0 :(得分:1)

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

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

重要性过滤器将保存字符串数组,例如[“ Low”,“ Medium”,“ High”]。

单击过滤器按钮时,如果过滤器是布尔型或已从数组中追加/删除,则将对其进行切换:

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(($0.bulletinVersion?.bulletin?.importance?.name)!)})
        }
    }

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

    }

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

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

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

但是,感谢所有评论提供其他解决方案的人,您真的帮助我跳出了思维框! :)

答案 1 :(得分:0)

我不确定您要问什么,但是可以。首先,您可以格式化代码以使其更具可读性。...我知道多个返回点被认为是不好的,但是潮流似乎对此有所改变。我将按重要性顺序挑选案例,并返回您可以找到的任何确定的布尔值。例如(未经验证的代码,因为我不知道什么是公告和范围):

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: {$0 == "Low" || $0 == "Normal" || $0 == "High"})
        && (scopes.contains(bulletin.read(i: bulletin.firstReadDate) {
        return true
    }

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

请注意,这些子句中的每一个都会测试true,并在适当时返回它,因此一旦找到true情况,函数就会立即返回。 tst的顺序可能会影响逻辑。

我会考虑使用一种采用公告,范围并返回true或false的方法来创建协议。

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

(奖金:请注意使用这种设计模式更改逻辑有多么容易)