【问题标题】:Scala immutable Map like datastructure that has constant/effective constant lookup具有常量/有效常量查找的 Scala 不可变 Map 类数据结构
【发布时间】:2015-10-16 13:48:15
【问题描述】:

在为 Scala 设计 JSON AST 时,我们意识到遇到了一个问题(可以在此处更详细地描述 https://github.com/json4s/json4s-ast/issues/8),理想情况下,我们希望用 Map 结构表示 JObject(JSON 对象)要么保留其键的顺序,要么使用默认的Ordering 按键排序,该默认Ordering 具有常量或有效常量查找时间。

我们需要保留顺序或保证键排序的东西的原因是,当有人序列化 JValue 时,我们需要确保它总是为相同的 JValue 输出相同的 JSON(最明显的情况是缓存 JValue 序列化)

问题在于 Scala 标准库似乎没有不可变的 Map 数据结构,该数据结构通过 O(c) 或 O(eC) 查找时间按键保留/排序(参考 http://docs.scala-lang.org/overviews/collections/performance-characteristics.html

有谁知道在 Scala 集合库之后的某个地方是否存在这种数据结构的实现(或者即使这样的数据结构普遍存在)?

【问题讨论】:

  • 有 SortedMap 但我找不到任何关于它的性能的信息。如果你真的没有找到任何东西,尽管你可以使用 HashMap 和将索引映射到键的 Array/HashMap 来制作自己的东西。
  • SortedMap 是一个抽象特征。它在 Scala 中的默认实现是 TreeMap,它具有日志查找(而不是 c/eC)
  • 为什么不想单独存储有序键序列?类似(Seq[String], Map[String, AnyRef])
  • 主要是由于内存的原因,这是一个通用的 JSON AST 数据类型,它可以保存大量的 JSON 数据。另外,除非我弄错了,否则这意味着我们必须创建自己的集合来实现Scala sortedMap 接口,因为我们希望用户将JObject 中的type 视为标准映射

标签: json scala data-structures immutability scala-collections


【解决方案1】:

一般来说,您无法在恒定时间内进行排序,因此使用Ordering 是正确的。

我知道实际上没有任何不可变的数据结构可以让你在任意位置添加和删除并保持性能不变(你能得到的最好的是O(log N),尽管有些人喜欢假装如果基于对数足够大,它“实际上是恒定的”)。

所以你的要求是不可能的。

但作为备用,TreeMap 对于排序的键来说还不错。对于O(log N) 解决方案,它非常有效。

对于正确顺序的键,一般需要维护三个映射:索引到键、键到索引和键到值。键的索引应该是TreeMap,这样你就可以按顺序走。其他的可以是任何东西。基本思想是,当你想添加一个键值对时,你增加索引并将 (index -> key) 添加到第一个映射和 (key -> index) 到第二个映射。然后当你按顺序走时,你沿着 index-to-key map 走,并在 key-value map 中查找。当您按键删除时,您会找到带有键到索引映射的索引,因此您也可以从索引到键映射中删除它。

【讨论】:

  • 您知道TreeMap 在查找/创建方面的性能是否类似于Vector?根据 scala 文档,Vector 是有效的常量查找,而 TreeMap 只是 log(不确定它们是否真的意味着 O(log N))。我想如果它实际上是 O(log N)),那么它与Vector 几乎相同。如果是这样,这也意味着文档是错误的
  • @mdedetrich 向量是分层数据结构,因此查找和更新是 O(log(N))。只是分支因子如此之高,以至于人们认为它对于典型尺寸实际上是恒定的。对于您的情况,现在只需使用 s.c.i.TreeMap。
【解决方案2】:

经过与其他人的深思熟虑,我们似乎将维护 2 个数据结构(一个向量和一个映射,即https://github.com/json4s/json4s-ast/issues/8#issuecomment-125025604),这基本上就是@Aivean 提到的。性能比潜在的内存使用更重要。

如果你需要排序,TreeMap 确实是最快的结构,它确实有 O(log(n)),没有排序你有标准的不可变 Map,即 O(n(log(n) )(Haskell 也有 Data.Map,其工作方式类似)。

感谢您的回答!

【讨论】:

    猜你喜欢
    • 2021-12-28
    • 2014-08-28
    • 2013-03-15
    • 2011-12-27
    • 1970-01-01
    • 2011-10-24
    • 2012-11-22
    • 1970-01-01
    • 2011-04-25
    相关资源
    最近更新 更多