将Java树映射代码迁移到Scala?
我正在将我的Java代码库迁移到纯Scala,我被卡住了。我有一个IntervalMap的实现,也就是一个数据结构,它可以让你有效地将范围将Java树映射代码迁移到Scala?,java,scala,scala-collections,treemap,treeset,Java,Scala,Scala Collections,Treemap,Treeset,我正在将我的Java代码库迁移到纯Scala,我被卡住了。我有一个IntervalMap的实现,也就是一个数据结构,它可以让你有效地将范围[从,到]映射到值,其中设置,删除和获取操作都是O(logn)(与IntervalTree或SegmentTree略有不同) 这段代码使用了Java的Java.util.TreeMaps,在迁移到Scala时,我遇到了两个大问题: Scala没有mutable.TreeMap-我决定使用mutable.TreeSet(奇怪的是Scala有mutable.Tre
[从,到]
映射到值,其中设置
,删除
和获取
操作都是O(logn)
(与IntervalTree或SegmentTree略有不同)
这段代码使用了Java的Java.util.TreeMaps
,在迁移到Scala时,我遇到了两个大问题:
Scala没有mutable.TreeMap
-我决定使用mutable.TreeSet
(奇怪的是Scala有mutable.TreeSet
,但没有mutable.TreeMap
)来存储键并将值存储在辅助mutable.Map
。这是一个令人不快的黑客行为,但有没有更好的方法
下一个问题是Scala的可变。TreeSet
与java.util.TreeSet
的ceilingKey
,FloorRentry
,pollFirst
,pollLast
没有等价物,它们都是java中的O(logn)
操作
那么,如何最好地将代码迁移到Scala?在这些情况下,最佳做法是什么?我真的不想编写自己的树实现。有没有一种更惯用的Scala方式来编写我不知道的间隔图?还是有一些著名的图书馆?或者Scala只是简单地在这里吸吮它的gimpedtreeset和不存在的TreeMaps。当然,我可以在Scala中使用Java的TreeMap
,但这太难看了,我失去了所有优秀的Scala集合特性,我也可以使用Java
下面是我当前的Java代码:不幸的是,答案是只使用JavaTreeMap
类
Scala并没有自己的所有副本,这是最显著的例外之一。它与Java兼容的原因之一是,您不必重新发明每个轮子
您仍然希望使用Scala的原因是,并非您编写的每一段代码都与此树映射有关。您的IntervalMap
可以是ScalaIntervalMap
;您只需在内部使用JavaTreeMap来实现它。或者您可以在Scala中使用不可变版本,它现在对于不可变版本的性能相当好
也许在2.11或2.12中会有一个可变的树形图
;它需要有人编写、测试、优化等等,但我认为拥有它并没有哲学上的异议。您似乎想使用漂亮的Scala collections功能。我认为你不需要重新实施你的课程
你看过scala.collection.JavaConversions吗
您可以采用类似的方法使用包装器,然后相应地实现所需的方法。您可能需要在如何定义和使用地图特有的方法方面更具创造性,但这不应该是什么大问题
我希望这能给你一个想法。如果您需要更多的指导,请告诉我,我可以帮您解决(看起来您已经有一段时间没有问了)。1)在内部使用不可变树映射有什么问题?它的效率和可变树映射差不多,一切都在O(logn)中完成
2) 在Scala版本中,没有ceilingKey
和floorKey
,而是有from
和to
的方法,这些方法基本相同,但返回的是整个子树而不是单个条目
Java代码的完整1:1端口:
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))
Segment
类应该设置为private[yourPackage]
,应该添加一些文档。Scala 2.12具有mutable.TreeMap
最后:该链接并没有真正回答我关于如何实际迁移代码的问题。最佳实践/习惯用法等是什么?最后,我仍然没有一个与floorrentry
等价的东西。在著名的Scala库中是否有mutable.TreeMap
和/或IntervalMap
本身的实现?对于TreeMap是from
和to
,O(logn)??如果不是,在代码中,操作不是对数的。。。顺便说一句,这是我在Scala中的实现(它是O(n)而不是O(logn),其中n是段数:我上面链接的Java是O(logn)。为什么不应该在O(logn)中呢?这与ceil
和floor
的操作大致相同,但不是沿着树走到叶子节点,而是沿着树走,并将路径存储在大小为O(log n)的列表中
,最终修剪所访问节点的两个子节点中的一个子节点。如果需要,可以在此处查看底层RedBlackTree的实现:,尤其是doFrom
方法,它似乎是实际from
方法的“递归工作马”。
{}
{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