按键集过滤地图

时间:2012-01-27 09:08:42

标签: scala

是否有一个快捷方式来过滤Map,只保留给定Set中包含密钥的条目?

以下是一些示例代码

scala> val map = Map("1"->1, "2"->2, "3"->3)
map: scala.collection.immutable.Map[java.lang.String,Int] = Map(1 -> 1, 2 -> 2, 3 -> 3)

scala> map.filterKeys(Set("1","2").contains)
res0: scala.collection.immutable.Map[java.lang.String,Int] = Map(1 -> 1, 2 -> 2)

我正在寻找比这短的东西。

3 个答案:

答案 0 :(得分:50)

回答问题

您可以利用Set[A]是谓词的事实;即A => Boolean

map filterKeys set

这是在工作:

scala> val map = Map("1" -> 1, "2" -> 2, "3" -> 3)
map: scala.collection.immutable.Map[java.lang.String,Int] = Map(1 -> 1, 2 -> 2, 3 -> 3)

scala> val set = Set("1", "2")
set: scala.collection.immutable.Set[java.lang.String] = Set(1, 2)

scala> map filterKeys set
res0: scala.collection.immutable.Map[java.lang.String,Int] = Map(1 -> 1, 2 -> 2)

或者如果您愿意:

scala> map filterKeys Set("1", "2")
res1: scala.collection.immutable.Map[java.lang.String,Int] = Map(1 -> 1, 2 -> 2)

谓词

在谓词周围设置一些包装实际上非常有用。像这样:

scala> class PredicateW[A](self: A => Boolean) {
   | def and(other: A => Boolean): A => Boolean = a => self(a) && other(a)
   | def or(other: A => Boolean): A => Boolean = a => self(a) || other(a)
   | def unary_! : A => Boolean = a => !self(a)
   | }
defined class PredicateW

隐式转换:

scala> implicit def Predicate_Is_PredicateW[A](p: A => Boolean) = new PredicateW(p)
Predicate_Is_PredicateW: [A](p: A => Boolean)PredicateW[A]

然后你可以使用它:

scala> map filterKeys (Set("1", "2") and Set("2", "3"))
res2: scala.collection.immutable.Map[java.lang.String,Int] = Map(2 -> 2)

scala> map filterKeys (Set("1", "2") or Set("2", "3"))
res3: scala.collection.immutable.Map[java.lang.String,Int] = Map(1 -> 1, 2 -> 2, 3 -> 3)

scala> map filterKeys !Set("2", "3")
res4: scala.collection.immutable.Map[java.lang.String,Int] = Map(1 -> 1)

这可以扩展到xornand等等,如果你包含符号unicode可以使代码令人惊讶:

val mustReport = trades filter (uncoveredShort ∨ exceedsDollarMax)

val european = { 
  val Europe = (_ : Market).exchange.country.region == Region.EU
  trades filter (_.market ∈: Europe)
}

答案 1 :(得分:9)

切向提示,以防您在@oxbow_lakes的回答中遵循PredicateW的想法:

在函数式编程中,我们的目标是更通用和可组合的抽象,而不是定义ad hoc函数。对于这种特殊情况,Applicative符合要求。

Set本身就是函数,Applicative的{​​{1}}实例让我们将函数提升到上下文。换句话说,您可以将[B]Function1[A, B]类型的函数(例如(Boolean, Boolean) => Boolean||等)提升为&&。 (Here你可以找到关于这个解除概念的一个很好的解释。)

但是,数据结构(A => Boolean, A => Boolean) => (A => Boolean)本身有一个Set实例,与Applicative实例相比,它更受青睐。为了防止这种情况,我们必须明确告诉编译器将给定集视为函数。我们为此定义了以下内容:

[B]Applicative[A => B]

现在使用这个scala> implicit def setAsFunction[A](set: Set[A]) = new { | def f: A => Boolean = set | } setAsFunction: [A](set: Set[A])java.lang.Object{def f: A => Boolean} scala> Set(3, 4, 2).f res144: Int => Boolean = Set(3, 4, 2) 善良。

Applicative

注意:以上所有内容都需要Scalaz。

答案 2 :(得分:8)

很抱歉,不能直接回答您的问题,但如果您知道要删除的密钥(而不是您要保留的密钥),则可以执行以下操作:

map -- Set("3")