【问题标题】:Scala API: view IndexedSeq[T] as Map[Int, T]Scala API:将 IndexedSeq[T] 视为 Map[Int, T]
【发布时间】:2014-08-20 12:42:14
【问题描述】:

简单地说,Scala 集合库中是否有一种方法可以为索引序列提供类似地图的视图,使用索引作为键?

我有以下特点(16 个元素的限制是由外部 API 设计和强制执行的)

trait Container[T >: Null]
{
    private val ElemsLimit = 16 // block's meta is 4-bit
    private var table: Seq[T] = null

    protected def register(elems: (Int, T)*)(implicit manifest: Manifest[T]) =
    {
        if (table != null)
            throw new IllegalStateException("Already initialized")
        val array = Array.fill[T](ElemsLimit)(null)
        elems foreach { el => array(el._1) = el._2 }
        table = array
    }

    def elem(idx: Int) = table(idx)
    def allElems = table.zipWithIndex.filter(_  != null) // some mapView instead of zipWithIndex
}

我知道我可以构建不可变地图,坦率地说,它可以很好地满足我的目的。我自己也可以为此编写 MapView。虽然我真的很感兴趣,如果某处有现有的解决方案。或者,也许,我错过了数组支持的不可变映射。

谢谢。

【问题讨论】:

    标签: scala


    【解决方案1】:
    IndexedSeq("A", "B").zipWithIndex.map(_.swap).toMap
    

    结果将是Map[Int,String] = Map(0 -> A, 1 -> B)

    foldLeft 的替代方案可能是:

    IndexedSeq("A", "B").foldLeft(0 -> Map.empty[Int,String]) {
      case ((i, m), v) => i+1 -> (m + (i -> v)) // next state is
      // incremented index & updated map
    }._2 // keep only the built map, not the last processed index
    

    【讨论】:

    • 我搜索“视图”解决方案,即不会创建不必要的完整副本的解决方案。如果我需要 zipWithIndex,那么我会这样做。
    【解决方案2】:

    我看到的问题是修改结果地图,例如删除或添加元素。那应该如何表现?对于一个简单的可选get 方法,您可以尝试提升:

    val xs = "hallo".toVector
    val m = xs.lift
    m(-1) // None
    m(1)  // Some('a')
    

    否则您需要编写自己的包装器并决定如何处理修改。例如

    class IndexMap[A](peer: IndexedSeq[A]) extends collection.immutable.Map[Int, A] {
      private def unsupported(name: String): Nothing = 
        throw new UnsupportedOperationException(name)
    
      def +[B1 >: A](kv: (Int, B1)): collection.immutable.Map[Int, B1] = 
        unsupported("+")
    
      def -(key: Int): collection.immutable.Map[Int, A] = unsupported("-")
    
      def get(key: Int): Option[A] = if (key < 0 || key >= peer.size) None 
        else Some(peer(key))
    
      def iterator: Iterator[(Int, A)] = peer.zipWithIndex.iterator.map(_.swap)
    }
    
    val im = new IndexMap(xs)
    
    im.get(-1)  // None
    im.get(1)   // Some('a')
    

    或者,也许,我错过了由数组支持的不可变映射。

    据我所知,HashMap(默认的不可变映射实现)已经使用数组,尽管可能不如普通索引序列高效:

    val hm = xs.zipWithIndex.map(_.swap)(collection.breakOut): Map[Int, Char]
    val ht = hm.asInstanceOf[collection.immutable.HashMap.HashTrieMap[_, _]]
    val mm = ht.getClass.getMethod("elems")
    mm.setAccessible(true)
    val arr = mm.invoke(ht)  // Array(Map(0 -> h), Map(1 -> a), ...)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-27
      • 1970-01-01
      • 2022-01-16
      • 1970-01-01
      • 2010-10-14
      • 2011-06-27
      • 1970-01-01
      相关资源
      最近更新 更多