簡體   English   中英

將Java TreeMap代碼遷移到Scala?

[英]Migrating Java TreeMap code to Scala?

我正在將我的Java代碼庫遷移到純Scala,我仍然堅持使用這一段代碼 我有一個讓你有效地映射范圍的IntervalMap即數據結構的實現[from,to]valuessetdeleteget操作都是O(log n) (從IntervalTree或線段樹略有不同)。

這段代碼使用Java的java.util.TreeMaps ,在遷移到Scala時,我遇到了兩個大問題:

  1. Scala沒有mutable.TreeMap - 我決定使用mutable.TreeSet (奇怪的是Scala有mutable.TreeSet但沒有mutable.TreeMap )來存儲密鑰並將值存儲在輔助的mutable.Map 這是一個不愉快的黑客,但還有更好的方法嗎?

  2. 下一個問題是Scala的mutable.TreeSet沒有java.util.TreeSetceilingKeyfloorEntrypollFirstpollLast等同於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版本中,沒有ceilingKeyfloorKey ,而是一個具有fromto方法基本相同,但返回整個子樹而不是單個條目。

完整的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.TreeMaphttps//github.com/scala/scala/pull/4504

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM