我目前正在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谓词将仅显示与所有过滤器匹配的公告。 因此,“未读+未签名+高”将在未读和未签名的所有重要公告中显示它们。
答案 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
(奖金:请注意使用这种设计模式更改逻辑有多么容易)