2013-04-12 12 views
5

Ben grails içinde özyinelemeli alanı sınıfı tanımlanmıştır:Yinelemeli kapatma kullanarak bir listeden bir ağaç hiyerarşisini nasıl oluşturabilirim?

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 
    } 

Ben İşlerin bir listesi var, ancak hiyerarşi yapı henüz inşa edilmez. Benim ihtiyacım kodu ima dayanarak bu eserler arasında hiyerarşik bir ilişki inşa etmektir

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

: gibi yapı görünüyor. Örneğin. A.1 A'nın ilk çocuk çalışmasıdır; B.1.1, ebeveyn B çalışması olan B.1 çalışmasının ilk çocuğudur. Groovy'nin, bu tür hiyerarşik yapıyı inşa etmek için tekrar eden kapanışları desteklediğini biliyorum. Groovy resmi belgelerinde, JN2515 Fibonacci sayı örneği gibi Groovy özyineli kapatmayı kullanarak hedefime nasıl ulaşabilirim? Çok teşekkürler!

cevap

3

bunu beğenin ...? Ben Grails ile biraz paslı değilim, ama ben akıllı bir şekilde koleksiyonları eşlenen yönetilen hatırlamak görünüyor

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

Aydınlanmış kod için çok teşekkürler. Yukarıdaki kod örnek listesi için çalışır: çalışır. Ya A.1.2'ye ihtiyacım varsa, A.1'e aittir; A.2.2 çalışması A.2'nin ikinci çocuğu mu? Sadece biraz sorumu düzenle. –

+0

SubWorks'ün düzenli bir şekilde olmasını istiyorsanız, veri yapınızı değiştirmeniz gerekir. Buraya bakın, http://grails.org/doc/latest/guide/GORM.html#sets,ListsAndMaps. SortedSet'i kullanmak ve Work sınıfında compareTo yöntemini uygulamak istediğinizi düşünüyorum. –

1

çalışabilir hatta bu anonim şeklinde yanlışlıkla olmazsam

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

Bunu yaparsanız: work1.parentWork = work2 sonra work1 in work2.subWorks doğrulayacaktır. Bu durumda, yapmanız gereken tek şey, her iş için parentWork'u ayarlamaktır ve bunun için herhangi bir karmaşık hesaplama yapmanız gerekmez: X.Y.Z ana işi X.Y, ve X ana işi hiçbiri olmayacaktır. :

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

Ayrıca çok parlak görünüyor! –