[英]Migrating Java TreeMap code to Scala?
我正在將我的Java代碼庫遷移到純Scala,我仍然堅持使用這一段代碼 。 我有一個讓你有效地映射范圍的IntervalMap即數據結構的實現[from,to]
到values
在set
, delete
和get
操作都是O(log n)
(從IntervalTree或線段樹略有不同)。
這段代碼使用Java的java.util.TreeMaps
,在遷移到Scala時,我遇到了兩個大問題:
Scala沒有mutable.TreeMap
- 我決定使用mutable.TreeSet
(奇怪的是Scala有mutable.TreeSet
但沒有mutable.TreeMap
)來存儲密鑰並將值存儲在輔助的mutable.Map
。 這是一個不愉快的黑客,但還有更好的方法嗎?
下一個問題是Scala的mutable.TreeSet
沒有java.util.TreeSet
的ceilingKey
, floorEntry
, pollFirst
, pollLast
等同於Java中的所有O(log n)
操作。
那么,我怎樣才能最好地將我的代碼遷移到Scala? 這些情況下的最佳做法是什么? 我真的不想編寫自己的樹實現。 有沒有更慣用的Scala編寫IntervalMaps的方式,我不知道? 或者那里有一些有信譽的圖書館? 或者Scala只是簡單地用它的gimped TreeSet和不存在的TreeMaps來吸吮。 當然我可以在Scala中使用Java的TreeMap
,但這很難看,我失去了所有不錯的Scala集合功能,我不妨使用Java。
這是我目前的Java代碼: https : //gist.github.com/pathikrit/5574521
不幸的是,答案只是使用Java TreeMap
類。
Scala沒有自己的所有副本,這是最值得注意的例外之一。 與Java兼容的原因之一是您不必重新發明每個輪子。
您仍然希望使用Scala的原因是您編寫的所有代碼都不是關於此TreeMap的 。 您的IntervalMap
可以是Scala IntervalMap
; 您只需在內部使用Java TreeMap
來實現它。 或者你可以在Scala中使用不可變版本,它現在對於不可變版本表現得相當不錯。
也許在2.11或2.12中會有一個可變的TreeMap
; 它需要有人寫它,測試它,優化它等等,但我不認為有這個有哲學上的反對意見。
1)內部使用不可變TreeMap有什么問題? 它或多或少與可變樹映射一樣高效,在O(log n)中執行所有操作。
2)在Scala版本中,沒有ceilingKey
和floorKey
,而是一個具有from
和to
方法基本相同,但返回整個子樹而不是單個條目。
完整的1:1 Java代碼端口:
import scala.collection._
import scala.collection.immutable.TreeMap
case class Segment[T](start: Int, end: Int, value: T) {
def contains(x: Int) = (start <= x) && (x < end)
override def toString = "[%d,%d:%s]".format(start, end, value)
}
class IntervalMap[T] {
private var segments = new TreeMap[Int, Segment[T]]
private def add(s: Segment[T]): Unit = segments += (s.start -> s)
private def destroy(s: Segment[T]): Unit = segments -= s.start
def ceiling(x: Int): Option[Segment[T]] = {
val from = segments.from(x)
if (from.isEmpty) None
else Some(segments(from.firstKey))
}
def floor(x: Int): Option[Segment[T]] = {
val to = segments.to(x)
if (to.isEmpty) None
else Some(segments(to.lastKey))
}
def find(x: Int): Option[Segment[T]] = {
floor(x).filter(_ contains x).orElse(ceiling(x))
}
// This is replacement of `set`, used as myMap(s,e) = v
def update(x: Int, y: Int, value: T): Unit = {
require(x < y)
find(x) match {
case None => add(Segment[T](x, y, value))
case Some(s) => {
if (x < s.start) {
if (y <= s.start) {
add(Segment[T](x, y, value))
} else if (y < s.end) {
destroy(s)
add(Segment[T](x, y, value))
add(Segment[T](y, s.end, s.value))
} else {
destroy(s)
add(Segment[T](x, s.end, value))
this(s.end, y) = value
}
} else if (x < s.end) {
destroy(s)
add(Segment[T](s.start, x, s.value))
if (y < s.end) {
add(Segment[T](x, y, value))
add(Segment[T](y, s.end, s.value))
} else {
add(Segment[T](x, s.end, value))
this(s.end, y) = value
}
} else {
throw new IllegalStateException
}
}
}
}
def get(x: Int): Option[T] = {
for (seg <- floor(x); if (seg contains x)) yield seg.value
}
def apply(x: Int) = get(x).getOrElse{
throw new NoSuchElementException(
"No value set at index " + x
)
}
override def toString = segments.mkString("{", ",", "}")
}
// little demo
val m = new IntervalMap[String]
println(m)
m(10, 20) = "FOOOOOOOOO"
m(18, 30) = "_bar_bar_bar_"
m(5, 12) = "bazzz"
println(m)
for (x <- 1 to 42) printf("%3d -> %s\n",x,m.get(x))
結果:
{}
{5 -> [5,12:bazzz],12 -> [12,18:FOOOOOOOOO],18 -> [18,20:_bar_bar_bar_],20 -> [20,30:_bar_bar_bar_]}
1 -> None
2 -> None
3 -> None
4 -> None
5 -> Some(bazzz)
6 -> Some(bazzz)
7 -> Some(bazzz)
8 -> Some(bazzz)
9 -> Some(bazzz)
10 -> Some(bazzz)
11 -> Some(bazzz)
12 -> Some(FOOOOOOOOO)
13 -> Some(FOOOOOOOOO)
14 -> Some(FOOOOOOOOO)
15 -> Some(FOOOOOOOOO)
16 -> Some(FOOOOOOOOO)
17 -> Some(FOOOOOOOOO)
18 -> Some(_bar_bar_bar_)
19 -> Some(_bar_bar_bar_)
20 -> Some(_bar_bar_bar_)
21 -> Some(_bar_bar_bar_)
22 -> Some(_bar_bar_bar_)
23 -> Some(_bar_bar_bar_)
24 -> Some(_bar_bar_bar_)
25 -> Some(_bar_bar_bar_)
26 -> Some(_bar_bar_bar_)
27 -> Some(_bar_bar_bar_)
28 -> Some(_bar_bar_bar_)
29 -> Some(_bar_bar_bar_)
30 -> None
31 -> None
32 -> None
33 -> None
34 -> None
35 -> None
Segment
類應設置為private[yourPackage]
,應添加一些文檔。
看起來你想要使用漂亮的Scala集合功能。 我認為你不需要重新實現你的課程。
你見過scala.collection.JavaConversions
嗎?
您可以使用包裝器遵循類似的方法,然后相應地實現您想要的方法。 您可能需要更具創造性,如何定義,然后使用您的地圖類型獨有的方法,但不應該是一個大問題。
我希望這會給你一個想法。 如果你需要更多的指導我可以告訴我,我可以幫助你(看起來你已經有一段時間了)。
Scala 2.12最近有了mutable.TreeMap
: https : //github.com/scala/scala/pull/4504
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.