Scala构建不可变映射,用于... yield理解,在重复键上抛出异常

时间:2016-11-11 16:11:14

标签: scala

这是挑战(Scala 2.11):

(for (i <- -3 to 3) yield (f(i), i)).toMap

f():Int =&gt; Int是一个未知的参数,它被传递到我的代码中。生成的映射将是有界空间上函数的“逆”。

如果

,这将正常工作
f(i: Int) = i * 2 

但如果

NOT 工作正常
f(i: Int) = i * i

因为,例如f(-2)= 4和f(2)= 4这使得重复键和第二个覆盖第一个

我的问题是:当有重复的键时,我怎么能抛出IllegalArgumentException ...(即告诉用户他/她的功能在有界空间内不是“可逆的”)

我知道我可以使用mutable.Map并编写一个循环,而不是用于理解(例如使用尾递归),它在每次迭代时执行“map.get”并且如果已经存在,则抛出... 。,否则加入地图。

有不可改变的方法吗?

对于额外的积分,我还需要检查f(i)是否在界限内(-3..3)并忽略如果不是......

2 个答案:

答案 0 :(得分:1)

我想你可以在你的范围内弃左,而不是用于理解,例如:

(-3 to 3).foldLeft(Map.empty[Int, Int]){ case (result, next) => 
   val answer = f(next)
   result.get(answer).fold(result + answer -> next)(_ => throw new IllegalArgumentException)
}

我没有仔细检查所有使用的类的API,因此代码可能不会编译,但类似的东西应该。

答案 1 :(得分:1)

将其分解为更小的步骤,很明显for-comprehension返回一个向量。 toMap是创建地图的原因。但是,在您的方案中,foldLefttoMap更合适。

  val f = (i:Int) => i * i
  val pairs = for (i <- -3 to 3) yield f(i) -> i
  val result = pairs.foldLeft(Map.empty[Int, Int]) { case (map, (k, v)) =>
    if(map contains k)
      map //or throw IllegalArgumentException here
    else
      map + (k -> v)
  }
  println(result)

这里有更多的步骤(但功能完全相同)答案:

  val f = (i:Int) => i * i
  val pairs = for (i <- -3 to 3) yield f(i) -> i

  val zero = Map.empty[Int, Int]
  def putIfAbsent(map:Map[Int, Int], pair:(Int, Int)):Map[Int, Int] =
    pair match { case (k, v) =>
      if(map contains k)
        map
      else
        map + (k -> v)
    }

  val result = pairs.foldLeft(zero)(putIfAbsent)
  println(result)