list.find(closure)并针对该值执行

时间:2011-05-22 04:28:50

标签: grails groovy

真的我的问题是“下面的代码示例是否可以更小?基本上代码示例的目的是首先查看对象列表,找到最精细的(在这种情况下它是分支)然后根据查询向后查询它找到了什么对象。

1 - 如果找到分支,则将findAllBy返回分支

2 - 如果找到某个部门,则将findAllBy返回部门

3 - 如果找到组织,则将findAllBy返回给组织

目标是找到最精细的对象(这就是为什么顺序很重要),但是我需要有两个单独的块(一个用于定义对象,另一个用于检查它们是否存在)?或者可以将这两个命令组合成一个命令......

def resp
def srt = [sort:"name", order:"asc"]

def branch = listObjects.find{it instanceof Branch} 
def department = listObjects.find{it instanceof Department}
def organization = listObjects.find{it instanceof Organization}

resp = !resp && branch ? Employees.findAllByBranch(branch,srt) : resp
resp = !resp && department ? Employees.findAllByDepartment(department,srt) : resp
resp = !resp && organization ? Employees.findAllByOrganization(organization,srt) : resp

return resp

我在想的是这样的:

def resp
resp = Employees.findAllByBranch(listObjects.find{it instanceof Branch})
resp = !resp ? Employees.findAllByDepartment(listObjects.find{it instanceof Department}) : resp
resp = !resp ? Employees.findAllByOrganization(listObjects.find{it instanceof Organization}) : resp

但我相信会抛出异常,因为这些对象可能为null

3 个答案:

答案 0 :(得分:1)

修改
for循环更有效,因为你想要破坏第一个非null结果的处理(即在Groovy中我们不能用“return”或“break”中断闭包迭代)。

def resp   
for(clazz in [Branch,Department,Organization]) {  
    resp = Employees."findAllBy${clazz.name}"(listObjects?.find{it instanceof $clazz})  
    if(resp) return  
}  
if(resp) // do something...

<强>原始

List results = [Branch,Department,Organization].collect{clazz->  
    Employees."findAllBy${clazz.name}"(listObjects?.find{it instanceof $clazz})  
}

享受Groovy; - )

答案 1 :(得分:1)

我认为@virtualeyes nearly had it,而不是收集(正如他所说,你不能突破),你想使用一个find,因为它停止运行它得到的第一个有效结果:

List results = [Branch,Department,Organization].find { clazz->  
    Employees."findAllBy${clazz.name}"(listObjects?.find{it instanceof clazz})  
}

答案 2 :(得分:1)

您可以使用findResult将其缩短一点,而不是使用需要在外部进行def的变量的for循环:

def listObjects // = some predetermined list that you've apparently created
def srt = [sort:"name", order:"asc"]

def result = [Branch, Department, Organization].findResult { clazz -> 
    listObjects?.find { it.class.isAssignableFrom(clazz) }?.with { foundObj ->
        Employees."findAllBy${clazz.name}"(foundObj, srt)
    }
}

findResultfind类似,但它返回第一个非null项而不是项本​​身的结果。它避免了在循环之外需要单独的集合变量。

编辑:我之前所做的与我认为你正在寻找的行为并不完全相符(我不认为其他答案也是如此,但我可能会误解)。你必须确保在执行findAllBy之前在列表中找到了一些东西,否则你可能会撤回不是你正在寻找的空项目。

在实际的生产代码中,我实际上做的事情有点不同。我利用JVM类型系统只需要在找到第一个分支/部门/组织时,一次又一次地绕过listObjects短路:

def listObjects
def sort = [sort:"name", order:"asc"]

def result = listObjects?.findResult { findEmployeesFor(it, sort) }

...  // then have these methods to actually exercise the type specific findEmployeesFor

def findEmployeesFor(Branch branch, sort) { Employees.findAllByBranch(branch, sort) }
def findEmployeesFor(Department department, sort { Employees.findAllByDepartment(department, sort)}
def findEmployeesFor(Organization organization, sort { Employees.findAllByOrganization(organization, sort)}
def findEmployeesFor(Object obj, sort) { return null } // if listObjects can hold non/branch/department/organization objects

我认为这段代码实际上更清晰,它减少了我们遍历列表的次数以及我们需要进行的反射调用次数。