2013-04-12 13 views
5

ho definito la classe del dominio ricorsiva in graal:come si costruisce una gerarchia ad albero da una lista in groovy usando la chiusura ricorsiva?

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 
    } 

ho una lista dei lavori, ma la struttura gerarchia non è ancora costruito. La struttura si presenta come:

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

Che cosa ho bisogno è quello di costruire la relazione gerarchica tra queste opere, basato sul codice accennato. per esempio. A.1 è il primo figlio di A; B.1.1 è il primo figlio di B.1 lavoro, il cui genitore è B lavoro. So che Groovy supporta chiusure ricorsive per costruire questo tipo di struttura gerarchica. Come raggiungo il mio obiettivo utilizzando la chiusura ricorsiva di Groovy, come nell'esempio del numero di Fibonacci JN2515, nella documentazione ufficiale di Groovy? Mille grazie!

risposta

3

piace questo ...?

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

se non sono in errore anche in questa forma Anonim può funzionare

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

Mille grazie per il codice illuminato. Il codice sopra funziona per l'elenco di esempio: funziona. Cosa succede se ho bisogno di lavoro A.1.2 appartenere a A.1; A.2.2 lavoro è il secondo figlio di A.2? Modifica leggermente la mia domanda. –

+0

Se si desidera eseguire sottWorks in modo ordinato, è necessario modificare la struttura dei dati. Guarda qui, http://grails.org/doc/latest/guide/GORM.html#sets,ListsAndMaps. Penso che tu voglia usare SortedSet e implementare il metodo compareTo nella classe Work. –

1

Sono un po 'arrugginito con Grails, ma mi sembra di ricordare che è riuscita mappato le collezioni in modo intelligente , in modo tale che se lo fai: work1.parentWork = work2 quindi verificare work1 in work2.subWorks. In tal caso, è sufficiente impostare parentWork per ogni lavoro e non è necessario eseguire alcun calcolo complicato per questo: il lavoro principale di X.Y.Z sarà X.Y e il lavoro principale di X non sarà nessuno :

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

Sembra anche molto brillante! –

Problemi correlati