Scala代码美化 - 使用if语句循环2D数组

时间:2017-03-24 07:55:18

标签: arrays scala functional-programming

嘿,我对函数式编程很陌生,那么编写代码和平的最像scala的方式是什么?

var ANSWERS_ARRAY // Is array
for ((rows, i) <- SOME_2D_ARRAY.view.zipWithIndex)
      for ((col, j) <- rows.view.zipWithIndex)
        if (col == SOME_VALUE)
          // add tuple of (SOME_VALUE, (i,j)) to an ANSWERS_ARRAY

这里我循环遍历2D数组并检查指定的元素是否与条件匹配。如果是的话,我把它放到一个新的阵列。那有一两个班轮吗?因为这段代码很丑陋且效率低下。

2 个答案:

答案 0 :(得分:2)

一个简单的解决方案,使用zipWithIndex和for-comprehension:

 val SOME_2D_ARRAY: List[List[Int]] = ???
 val SOME_VALUE: Int = ???
 val ANSWERS_ARRAY: List[(Int, (Int, Int))] = for {
   (rows, i) <- SOME_2D_ARRAY.zipWithIndex
   (col, j) <- rows.zipWithIndex
   if col == SOME_VALUE
 } yield (SOME_VALUE, (i,j))

如果您想实现延迟搜索(如在您的代码段中),那么您可以实现它。请注意,在此版本中,ANSWERS_ARRAY是一个惰性集合。

 val ANSWERS_ARRAY = for {
   (rows, i) <- SOME_2D_ARRAY.view.zipWithIndex
   (col, j) <- rows.view.zipWithIndex
   if col == SOME_VALUE
 } yield (SOME_VALUE, (i,j))

答案 1 :(得分:1)

代码的逻辑起初并不是非常实用。

在函数式编程中,您通常会处理不可变数据,在该数据上应用函数来获取新的不可变值。在这里,你试图强制修改answer_array的值。

这样做的惯用方法如下:

val answerArray = my2DArray.zipWithIndex.flatMap {
  case (row, i) => row.zipWithIndex.filter{
    case (col, j) => col == someValue
  }.map {
    case (col, j) => (someValue, (i, j))
  }
}

这不是非常易读的代码,特别是初学者,所以让我们分解它:

  • 首先我们使用flatMap遍历我们的2D数组(带索引),它使用一个函数来对每个元素进行操作。此函数必须为每个元素返回另一个数组,并将所有这些数组展平为一个数组(因此flatMap中的“平面”)。

  • 数组的元素是初始数组的元素对,即一行及其索引,因此我们在这一对上进行模式匹配,以便能够正确定义我们的函数。

  • 现在,对于每一行,我们想做什么?只保留满足条件的元素,所以我们filter使用谓词(这只是函数返回Boolean的一个奇特名称),返回只包含满足条件的值的数组

  • 但是,我们不想要这些值,而是对它们进行转换,因此我们将map应用于数组。 mapflatMap相同,只是它的参数不需要返回数组,因为返回值不会被展平(它只是通过以下方式生成第一个数组的元素的图像数组)给定的功能)。

  • 我们想要对剩余元素应用什么功能?好吧,我们只想要三联(someValue, (i, j))

  • 请注意我使用了camelCase,这也是在scala中命名变量的惯用方法(虽然这没有必要)

好的,所以我们有一些很好的代码可以做我们想要的,但它不是很易读。值得庆幸的是,这种语言作为一种很好的语法糖,需要理解才能将flatMap s,mapfilter替换为更为迫切的风格。请注意,这只是为了方便编写代码,并且在编译时,代码将被我上面描述的内容(或接近它的内容)所取代。

val answerArray = for {
  (row, i) <- 2DArray.zipWithIndex
  (col, j) <- row.zipWithIndex
  if col == someValue
} yield (someValue, (i, j))
  • 每条<-行遍历rhs数组,将lhs名称分配给其元素(某些模式匹配作为奖励)

  • 每个if行代表我们要保留的值的条件

  • yield部分是我们想要在最终数组的每个元素中获取的值,具体取决于我们在每个数组中提取的值。