2016-07-13 4 views
0

나는 각 영역에 부모 영역이있을 수있는 매우 간단한 데이터베이스 테이블을 가지고있다.스칼라로 튜플에서 재귀 객체 그래프 만들기

mysql> describe region; 
+---------------+-------------+------+-----+---------+-------+ 
| Field   | Type  | Null | Key | Default | Extra | 
+---------------+-------------+------+-----+---------+-------+ 
| region_code | char(3)  | NO | PRI | NULL |  | 
| region_name | varchar(50) | NO |  | NULL |  | 
| parent_region | char(3)  | YES | MUL | NULL |  | 
+---------------+-------------+------+-----+---------+-------+ 

이제는이 데이터를 각각 동일한 유형의 부모가있는 사례 클래스의 Scala 개체 그래프로 수분을주고 싶습니다.

case class Region(code: String, name: String, parent: Option[Region]) 

다음 코드로이 작업을 수행합니다. 그것은 작동하지만 가능한 경우 피하고 싶습니다 중복 개체를 만듭니다.

class RegionDB @Inject() (db: Database) { 
    def getAll(): Seq[Region] = { 

    Logger.debug("Getting all regions.") 
    db.withConnection { implicit conn => 

     val parser = for { 
     code <- str("region_code") 
     name <- str("region_name") 
     parent <- str("parent_region").? 
     } yield (code, name, parent) 

     val results = SQL("SELECT region_code, region_name, parent_region from region").as(parser.*) 

     // TODO: Change this so it doesn't create duplicate records 
     def toRegion(record: (String, String, Option[String])): Region = { 
     val (code, name, parent) = record 
     val parentRecord = parent.map(p => results.find(_._1 == p)).getOrElse(None) 
     new Region(code, name, parentRecord.map(toRegion).orElse(None)) 
     } 

     val regions = results map toRegion 

     regions.foreach(r => Logger.debug("region: " + r)) 

     regions 
    } 
    } 
} 

나는 명령형으로 이것을하는 방법을 알고 있지만 기능적인 방법으로는 알지 못합니다. 재귀를 사용하여 표현할 수있는 표현 방법이 있어야한다는 것을 알고 있지만 알아낼 수는 없습니다. 어떻게 아십니까? 감사!

+0

당신은 링크를 주셔서 감사합니다 (그리고 코드를 청소) https://github.com/cchantep/acolyte/tree/10m-anorm-tutorial – cchantep

+0

에 모습을 가질 수 있지만 꽤 무엇을 아니다 나는 찾고 있었다. 이 예제는 재귀 적 구조가 아닌 계층 적 데이터 구조를 보여줍니다. 어떤 경우 클래스도 그들 자신의 인스턴스를 참조하지 않습니다. –

답변

0

이 문제는 지역 사례 클래스를 재구성하여 부모 영역이 var이고 자식 컬렉션을 추가함으로써 해결할 수있었습니다. 그것은 var하지만 오 잘없이 이렇게하는 것이 좋을 것입니다.

case class Region(code: String, name: String, subRegions: Seq[Region]){ 
    var parentRegion: Option[Region] = None 
    subRegions.foreach(_.parentRegion = Some(this)) 
} 

재귀는 루트에서 더 자연스럽게 진행됩니다.

def getAll(): Seq[Region] = { 

    Logger.debug("Getting all regions.") 
    db.withConnection { implicit conn => 

    val parser = for { 
    code <- str("region_code") 
    name <- str("region_name") 
    parent <- str("parent_region").? 
    } yield (code, name, parent) 

    val results = SQL("SELECT region_code, region_name, parent_region from region").as(parser.*) 

    def toRegion(record: (String, String, Option[String])): Region = { 
    val (regionCode, name, parent) = record 
    val children = results.filter(_._3 == Some(regionCode)).map(toRegion) 
     Region(regionCode, name, children) 
    } 

    val rootRegions = results filter(_._3 == None) map toRegion 

    rootRegions.foreach(r => Logger.debug("region: " + r)) 

    rootRegions 
    } 
}