2013-04-12 26 views
5

我定义Grails的递归域名类:如何使用递归闭包从groovy中的列表构建树层次结构?

class Work { 

    String code 
    String title 
    String description 
    static hasMany = [subWorks:Work] 
    static mappedBy = [subWorks: 'parentWork'] 

    Work getRootWork(){ 
    if(parentWork) return parentWork.getRootWork() 
     else return this 
    } 

    boolean isLeafWork(){ 
    return subWorks.isEmpty() 
    } 

    boolean isRootWork(){ 
    return !parentWork 
    } 

我有作品的名单,但层次结构尚未建成。该结构是这样的:

def works = [new Work(code:'A', title:'TitleA'), 
    new Work(code:'B', title:'TitleB'), 
    new Work(code:'A.1', title:'Titile A.1'), 
    new Work(code:'B.1', title:'Title B.1'), 
    new Work(code:'B.2', title:'Title B.2'), 
    new Work(code:'B.3', title:'Title B.3'), 
    new Work(code:'B.2.2', title:'Title B.2.2'), 
    new Work(code:'B.2.3', title:'Title B.2.3'), 
    new Work(code:'A.1.1', title:'Title A.1.1'), 
    new Work(code:'A.1.2', title:'Title A.1.2'),] 

我需要的是打造这些作品之间的层次关系,基于代码暗示。例如A.1是A的第一部小孩作品; B.1.1是B.1工作的第一个孩子,其父母是B工作。我知道Groovy支持递归闭包来构建这种层次结构。在Groovy官方文档中,如何使用Groovy递归闭包实现我的目标,例如JN2515 Fibonacci编号示例? 非常感谢!

回答

3

是这样的...?

def root = new Work(code:'*', title:'ROOT') 

def build 

build = { p, list -> 
    list.groupBy{it.code.split('\\.').first()}.each{ el, sublist -> 
    el = sublist[0]   
    el.parentWork = p 
    if(sublist.size()>1){ 
     build(el, sublist[1..-1]) 
    } 
    } 

} 
build(root, works.sort{it.code.length()}) 

如果我没有错,即使在这种anonim形式可能工作

def root = new Work(code:'*', title:'ROOT') 

{ p, list -> 
    list.groupBy{it.code.split('\\.').first()}.each{ el, sublist -> 
    el = sublist[0]   
    el.parentWork = p 
    if(sublist.size()>1){ 
     call(el, sublist[1..-1]) 
    } 
    } 

}(root, works.sort{it.code.length()}) 
+0

非常感谢您的启发代码。以上代码适用于示例列表:works。如果我需要A.1.2属于A.1的工作,该怎么办? A.2.2工作是A.2的第二个孩子吗?只需稍微编辑我的问题。 –

+0

如果您想以有序的方式使用subWorks,则必须更改数据结构。看这里,http://grails.org/doc/latest/guide/GORM.html#sets,ListsAndMaps。我想你想使用SortedSet并在Work类中实现compareTo方法。 –

1

我有点生疏的Grails,但我似乎记得它设法在一个智能的方式映射集合,如果你这样做:work1.parentWork = work2然后work1 in work2.subWorks将验证。如果是这样的话,你所需要做的就是为每项工作设置parentWork,并且你不需要为此做任何复杂的计算:X.Y.Z的父作品将是X.Y,并且X的父作品将是none :

def works = [new Work(code:'A', title:'TitleA'), 
    new Work(code:'B', title:'TitleB'), 
    new Work(code:'A.1', title:'Titile A.1'), 
    new Work(code:'B.1', title:'Title B.1'), 
    new Work(code:'A.1.1', title:'Title A.1.1')] 

def worksByCode = works.collectEntries { [it.code, it] } 

works.each { 
    if (it.code.contains('.')) { 
     def parentCode = it.code[0..it.code.lastIndexOf('.') - 1] 
     it.parentWork = worksByCode[parentCode] 
    } 
} 
+0

它看起来也非常辉煌! –