需要一个指南来以功能的方式调整这个嵌套的for循环

时间:2015-01-12 16:16:03

标签: scala functional-programming

我正在研究这个scala代码:

  case class M(a: String, b: Int)

  val mm1 = List(Map("a" -> "001", "b" -> 12), Map("a" -> "002", "b" -> 25), Map("a" -> "003", "b" -> 100))
  val mm2 = List(M("001", 12), M("004", 99), M("003", 100))

  def validate(mm1: List[Map[String, Any]], mm2: List[M]): Boolean = {

    for (m1 <- mm1) {
      var found = false
      val a = m1("a")

      // nested loop: iterate mm2
      breakable {
        for (m2 <- mm2) {
          if (a == m2.a) {
            assert(m1("b") == m2.b)
            found = true
            break  // if found just break
          }
        }
      }

      // All of elements in mm1 must exist in mm2.
      // We will know this if "found" variable is set to true.
      assert(found == true)
    }
    true
  }

基本上validate方法只是确保mm1中的所有值都存在于mm2中(基于“text”键/属性),反之则不是必需的。然后它还确保mm1和mm2的每个元素的属性值相等。

我正在尝试在函数式编程风格中转换validate方法。但是不知道如何处理所有mm1项目的检查应该是mm2。

这是我尝试理解的内容:

  def validate2(mm1: List[Map[String, Any]], mm2: List[M]): Boolean = {        
    for {
      m1 <- mm1
      a = m1("a")
      m2 <- mm2
    } {
      if (a == m2.a) {
        assert(m1("b") == m2.b)
      }
    }
    true
  }

不太好,因为我无法将var found = false置于理解之内。所以我无法检查mm1中的所有项目是否都存在于mm2中。

任何人都可以提供帮助或有更好的想法(可能使用递归或根本不使用var found)?

2 个答案:

答案 0 :(得分:2)

使用forall(它接受一个谓词,如果集合中的所有元素都满足它,则返回true)和exists(也使用谓词)可以非常清楚地写出来(在我看来) ,但只需要一场比赛):

def validate(mm1: List[Map[String, Any]], mm2: List[M]) = mm1.forall { m1 =>
  mm2.exists {
    case M(a, b) => a == m1("a") && b == m1("b")
  }
}

请注意,我没有使用assert因无效输入的异常而失败 - 这本身就不起作用,它打破了方法类型签名的隐式契约 - 如果我看到{{1}返回一个布尔值的方法,我假设如果参数有效则该值为true,否则为false。您可以使用一些异常和功能组合的混合来实现与原始版本相同的行为,但我强烈建议不要这样做。

我还建议避免地图上可能失败的查找(例如使用validate(...)get并明确处理错误的可能性),而不是使用getOrElse

答案 1 :(得分:0)

考虑这样的事情,或许:

val ms = mm2.map(m => m.a -> m.b).toMap
mm1.foreach { m => 
    assert(m.get(a).flatMap(ms.get).exists(_ == m("b")))
}

true