2017-05-09 19 views
0

是否有可能(甚至是值得)嘗試編寫下面的代碼塊而沒有var?它適用於一個變種。這不是面試,這是我第一次嘗試scala(來自java)。在純函數中使用var的工作scala代碼。這可能沒有var?

問題:儘可能地讓人們靠近劇院的前面,同時保持每個請求(例如Jones,4張門票)在一個劇院區域。從前面開始的劇院部分的大小爲6,6,3,5,5 ......等等。我試圖通過將所有潛在的票務請求組放在一起來完成此任務,然後選擇每個部分中最適合的組。

這裏是類。一個SeatingCombination是SeatingRequest(只是標識)的一個可能的組合及其ticketCount(S)的總和:

class SeatingCombination(val idList: List[Int], val seatCount: Int){} 
class SeatingRequest(val id: Int, val partyName: String, val ticketCount: Int){} 
class TheatreSection(val sectionSize: Int, rowNumber: Int, sectionNumber: Int) { 
    def id: String = rowNumber.toString + "_"+ sectionNumber.toString; 
} 

通過我們得到以下功能的時間... 1)所有可能的SeatingRequest的組合在SeatingCombination的列表中並按降序排列。 2.)所有TheatreSection按順序列出。

def getSeatingMap(groups: List[SeatingCombination], sections: List[TheatreSection]): HashMap[Int, TheatreSection] = { 
    var seatedMap = new HashMap[Int, TheatreSection] 
    for (sect <- sections) { 
     val bestFitOpt = groups.find(g => { g.seatCount <= sect.sectionSize && !isAnyListIdInMap(seatedMap, g.idList) }) 
     bestFitOpt.filter(_.idList.size > 0).foreach(_.idList.foreach(seatedMap.update(_, sect))) 
    } 
    seatedMap 
} 

def isAnyListIdInMap(map: HashMap[Int, TheatreSection], list: List[Int]): Boolean = { 
    (for (id <- list) yield !map.get(id).isEmpty).reduce(_ || _) 
    } 

我寫了沒有var的程序的其餘部分,但在這個迭代部分,它似乎是不可能的。也許我的實施策略是不可能的。從我讀過的內容看,純函數中的var仍然有效。但它一直困擾着我,我想不出如何去除var,因爲我的教科書告訴我要儘量避免它們,而我不知道我不知道什麼。

+2

它看起來像'foldLeft'工作。 – Nebril

回答

5

您可以使用foldLeftsections迭代與正在運行的狀態(並再次,裏面,你的狀態,反覆增加的部分中的所有IDS):

sections.foldLeft(Map.empty[Int, TheatreSection]){ 
    case (seatedMap, sect) => 
    val bestFitOpt = groups.find(g => g.seatCount <= sect.sectionSize && !isAnyListIdInMap(seatedMap, g.idList)) 
    bestFitOpt. 
     filter(_.idList.size > 0).toList. //convert option to list 
     flatMap(_.idList). // flatten list from option and idList 
     foldLeft(seatedMap)(_ + (_ -> sect))) // add all ids to the map with sect as value 
} 

順便說一句,您可以簡化使用existsmap.contains第二種方法:

def isAnyListIdInMap(map: HashMap[Int, TheatreSection], list: List[Int]): Boolean = { 
list.exists(id => map.contains(id)) 

}

list.exists(predicate: Int => Boolean)是一個布爾值,如果list中的任何元素的謂詞爲真,則爲true。

map.contains(key)檢查map是否定義在key

如果你想更加簡潔,你不需要給一個名稱謂詞的說法:

list.exists(map.contains) 
1

這裏是我如何能夠實現不使用mutable.HashMap ,由註釋使用foldLeft的建議是用來做什麼的:

class SeatingCombination(val idList: List[Int], val seatCount: Int){} 
class SeatingRequest(val id: Int, val partyName: String, val ticketCount: Int){} 
class TheatreSection(val sectionSize: Int, rowNumber: Int, sectionNumber: Int) { 
    def id: String = rowNumber.toString + "_"+ sectionNumber.toString; 
} 

def getSeatingMap(groups: List[SeatingCombination], sections: List[TheatreSection]): Map[Int, TheatreSection] = { 
    sections.foldLeft(Map.empty[Int, TheatreSection]) { (m, sect) => 
    val bestFitOpt = groups.find(g => { 
     g.seatCount <= sect.sectionSize && !isAnyListIdInMap(m, g.idList) 
    }).filter(_.idList.nonEmpty) 

    val newEntries = bestFitOpt.map(_.idList.map(_ -> sect)).getOrElse(List.empty) 
    m ++ newEntries 
    } 
} 

def isAnyListIdInMap(map: Map[Int, TheatreSection], list: List[Int]): Boolean = { 
    (for (id <- list) yield map.get(id).isDefined).reduce(_ || _) 
} 
2

簡單地改變varval應該這樣做:) 我想,你可能會問擺脫可變地圖,沒有的var(代碼中不需要爲var)。

這樣的事情通常是在scala中遞歸地編寫或使用foldLeft,就像其他答案建議的一樣。這裏是一個遞歸版本:

@tailrec 
    def getSeatingMap(
    groups: List[SeatingCombination], 
    sections: List[TheatreSection], 
    result: Map[Int, TheatreSection] = Map.empty): Map[Int, TheatreSection] = sections match { 
    case Nil => result 
    case head :: tail => 
     val seated = groups 
     .iterator 
     .filter(_.idList.nonEmpty) 
     .filterNot(_.idList.find(result.contains).isDefined)  
     .find(_.seatCount <= head.sectionSize) 
     .fold(Nil)(_.idList.map(id => id -> sect)) 
     getSeatingMap(groups, tail, result ++ seated) 
    } 

順便說一句,我不認爲你需要測試每個ID在列表中的地圖存在 - 應該足以只是看在第一位。如果不是每次檢查地圖以查看該組是否已經就座,您只需在分配該分區後立即將其從輸入列表中刪除即可。

@tailrec 
    def selectGroup(
     sect: TheatreSection, 
     groups: List[SeatingCombination], 
     result: List[SeatingCombination] = Nil 
    ): (List[(Int, TheatreSection)], List[SeatingCombination]) = groups match { 
    case Nil => (Nil, result) 
    case head :: tail 
     if(head.idList.nonEmpty && head.seatCount <= sect.sectionSize) => (head.idList.map(_ -> sect), result.reverse ++ tail) 
    case head :: tail => selectGroup(sect, tail, head :: result) 
    } 

,然後在getSeatingMap

... 
    case head :: tail => 
    val(seated, remaining) => selectGroup(sect, groups) 
    getSeatingMap(remaining, tail, result ++ seated) 
相關問題