我想基于类型的鉴别器将序列分组到序列图中Option,类似于groupBy方法的结果但是None丢弃了导致的值.或者,可能通过PartialFunction鉴别器进行分组并丢弃未定义部分功能的那些.
这是一个具体的例子:
我有一组名称和一组命名空间.一些(但不是全部)名称属于有效的名称空间,我想将那些名称分组到一个Map中,丢弃那些没有名称的名称.
目前我的解决方案相当于:
val names = List("ns1.foo", "ns2.bar", "ns2.baz", "froznit")
val namespaces = List("ns1", "ns2")
def findNamespace(n: String): Option[String] = namespaces.find(n.startsWith)
val groupedNames = names.groupBy(findNamespace).collect {
case (Some(ns), name) => (ns, name)
}
// Map((ns1,List(ns1.foo)), (ns2,List(ns2.bar, ns2.baz)))
Run Code Online (Sandbox Code Playgroud)
我对这个解决方案的关注是,使用names.groupBy(findNamespace),我正在创建一个中间Map,其中包含我不关心的所有名称None.如果我丢弃的名称数量变大,则该解决方案变得不那么有吸引力.
我试图避免这种情况有点像火车残骸,但是:
val groupedNames =
names.
map(n => (findNamespace(n), n)).
collect({ case (Some(ns), n) => (ns, n) }).
groupBy(_._1).
map({ case (ns, names) => (ns, names.map(_._2)) })
Run Code Online (Sandbox Code Playgroud)
如果你以更聪明的方式解决这个问题,它会是什么?
编辑:理想情况下,解决方案应该只findNamespace(name)为每个名称调用一次,并仅使用Option[String]值构建Map ,而不调用单独的hasNamespace(name)谓词.
避免收集丢弃名称的一种方法是使用flatMap:
names.flatMap(n => findNamespace(n) map (ns => (ns, n)))
.groupBy(_._1)
.map { case (ns, pairs) => (ns, pairs map (_._2)) }
Run Code Online (Sandbox Code Playgroud)
你可以通过理解来实现同样的目标:
(for (n <- names; ns <- findNamespace(n)) yield (ns, n))
.groupBy(_._1)
.map { case (ns, pairs) => (ns, pairs map (_._2)) }
Run Code Online (Sandbox Code Playgroud)
您可以使用 FoldLeft:
val gn = names.foldLeft(Map[String, List[String]]()){ case (acc, name) =>
findNamespace(name) match {
case Some(ns) => acc + (ns -> (name :: acc.get(ns).getOrElse(Nil)))
case _ => acc
}
}
Run Code Online (Sandbox Code Playgroud)
假设顺序无关紧要,否则您可以使用 反转值gn.mapValues(_.reverse)。
| 归档时间: |
|
| 查看次数: |
4392 次 |
| 最近记录: |