【问题标题】:Best way to filter and sort a Map by set of keys通过一组键过滤和排序地图的最佳方法
【发布时间】:2015-10-05 15:29:22
【问题描述】:

我有一个 Map 实例(不可变):

val source = Map(
    ("foo", "spam"),
    ("bar", "hoge"),
    ("baz", "eggs"),
    ("qux", "corge"),
    ("quux", "grault")
  )

并且我在源映射中可能存在或不存在某些顺序的键(Set 或 List):

baz
foo
quuuuux // does not exist in a source map

但是,用简洁的 scala 样式迭代源映射、通过我的键对其进行过滤并将过滤后的项目以与键相同的顺序放入结果映射中的最佳和最干净的方法是什么?

Map(baz -> eggs, foo -> spam)

附:为了澄清 - 结果映射中的键顺序必须与过滤键列表中的相同

【问题讨论】:

  • 您得到了两个答案 b/c “与键的顺序相同”可能意味着保留源的迭代顺序(甚至键集)或键应该是有序的。您的示例表明后者。

标签: scala


【解决方案1】:

如果你有:

val source = Map(
  "foo" -> "spam",
  "bar" -> "hoge",
  "baz" -> "eggs",
  "qux" -> "corge",
  "quux" -> "grault"
 )

val keys = List( "baz", "foo", "quuuux" )

那么,你可以:

import scala.collection.immutable.SortedMap

SortedMap(source.toSeq:_*).filter{ case (k,v) => keys.contains(k) }

【讨论】:

    【解决方案2】:
    val keys = List("foo", "bar")
    val map = Map("foo" -> "spam", "bar" -> "hoge", "baz" -> "eggs")
    
    keys.foldLeft(ListMap.empty[String, String]){ (acc, k) => 
      map.get(k) match {
        case Some(v) => acc + (k -> v)
        case None => acc
      }
    }
    

    这将遍历键,构建仅包含匹配键的映射。

    请注意,您需要一个ListMap 来保留键的顺序,尽管ListMap 的实现会以与它们插入相反的顺序返回元素(因为键作为列表的头部添加)

    LinkedHashMap 会确保准确的插入顺序,但它是一个可变数据结构。

    【讨论】:

    • 对不起,如果我真的想保留键的顺序,即使它不是字母顺序,我不应该使用例如 ListMap 而不是 SortedMap 吗?
    • ListMap 不保证键的顺序。当前的实现恰好保留了顺序(例如在地图上),但它不在规范中。
    • 我已经详细阐述了一点
    • 在下一个版本中仍然可以更改 ListMap 以按任何顺序执行此操作。 ListMap 保持秩序根本不是“合同”的一部分。
    【解决方案3】:

    如果您需要一个有序的Map,您可以使用带有自定义键顺序的TreeMap 之类的东西。所以给定

    import scala.collection.immutable.TreeMap
    
    val source = Map(
      ("foo", "spam"),
      ("bar", "hoge"),
      ("baz", "eggs"),
      ("qux", "corge"),
      ("quux", "grault")
    )
    val order: IndexedSeq[String] = IndexedSeq("baz", "foo", "quuuuux")
    implicit val keyOrdering: Ordering[String] = Ordering.by(order.indexOf)
    

    你有选择,要么遍历有序键:

    val result1: TreeMap[String, String] = order.collect {
      case key if source.contains(key) => key -> source(key)
    }(collection.breakOut)
    
    // or a bit shorter
    val result2: TreeMap[String, String] = order.flatMap { key => source.get(key).map(key -> _) }(collection.breakOut)
    

    或从源映射中过滤:

    val result3: TreeMap[String, String] = TreeMap.empty ++ source.filterKeys(order.contains)
    

    我不确定哪个效率最高,但我怀疑flatMap 可能最快,至少对于您的简单示例而言。不过,恕我直言,最后一个示例比其他示例更具可读性。

    【讨论】:

    • 我相信最后一个代码示例必须如下所示:val result3 = TreeMap.empty[String, String] ++ source.filterKeys(order.contains)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-28
    • 2012-08-02
    • 1970-01-01
    • 2018-02-07
    • 1970-01-01
    • 2020-10-10
    • 1970-01-01
    相关资源
    最近更新 更多