2013-04-12 12 views
5

zdefiniowałem rekurencyjnej klasy domeny w Grails:Jak zbudować hierarchię drzewa z listy w groovy przy użyciu zamknięcia rekursywnego?

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 
    } 

mam wykazu prac, ale hierarchia struktura nie jest jeszcze zbudowany. Struktura wygląda następująco:

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'),] 

Potrzebuję zbudować hierarchiczną relację między tymi pracami, w oparciu o wskazany kod. na przykład A.1 jest pierwszym dziełem dziecka A; B.1.1 jest pierwszym dzieckiem z pracy B.1, którego rodzicem jest B. Wiem, że Groovy wspiera rekursywne zamknięcia w celu zbudowania takiej hierarchicznej struktury. Jak osiągnąć cel, stosując zamknięcie rekurencyjne Groovy, takie jak przykład numer JN2515 Fibonacci, w oficjalnej dokumentacji Groovy? Wielkie dzięki!

Odpowiedz

3

Podoba ci się ...?

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()}) 

jeśli nie jestem w błędzie, nawet w tej formie anonim może działać

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

Wielkie dzięki za oświecony kod. Powyższy kod działa dla przykładowej listy: działa. Co jeśli potrzebuję pracy w A.1.2 należą do A.1; Praca A.2.2 jest drugim dzieckiem A.2? Po prostu delikatnie edytuj moje pytanie. –

+0

Jeśli chcesz, aby podstrony były uporządkowane, musisz zmienić strukturę danych. Zajrzyj tutaj, http://grails.org/doc/latest/guide/GORM.html#sets,ListsAndMaps. Myślę, że chcesz użyć SortedSet i zaimplementować metodę compareTo w klasie Work. –

1

jestem trochę zardzewiały z Grails, ale wydaje mi się, że ona zarządzana w sposób inteligentny odwzorowane kolekcje , tak, że jeśli to zrobisz: work1.parentWork = work2, następnie work1 in work2.subWorks zweryfikuje. Jeśli tak jest w przypadku, wszystko co musisz zrobić, to ustawić parentWork dla każdej pracy, nie trzeba wykonywać żadnych skomplikowanych obliczeń dla tego: praca dominującą X.Y.Z będzie X.Y, a praca dominującą X będzie nic :

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

Wygląda również bardzo genialnie! –

Powiązane problemy