如果条件为map中的部分参数

时间:2018-02-27 17:46:00

标签: scala

我了解如何在地图中使用if。例如,val result = list.map(x => if (x % 2 == 0) x * 2 else x / 2)

但是,我想只使用if作为部分参数。

val inputColumns = List(
  List(1, 2, 3, 4, 5, 6),   // first "column"
  List(4, 6, 5, 7, 12, 15)  // second "column"
)
inputColumns.zipWithIndex.map{ case (col, idx) => if (idx == 0) col * 2 else col / 10}
<console>:1: error: ';' expected but integer literal found.

inputColumns.zipWithIndex 
res4: List[(List[Int], Int)] = List((List(1, 2, 3, 4, 5, 6),0), (List(4, 6, 5, 7, 12, 15),1))

我搜索了错误信息但未找到解决方案。

为什么我的代码不合法​​&#39;在斯卡拉?有没有更好的方法来写它?基本上,我想做一个模式匹配,然后对其他参数做一些事情。

2 个答案:

答案 0 :(得分:3)

要以另一种方式解释您的问题,inputColumns的类型为List[List[Int]]。您可以在 Scala REPL 中验证这一点:

$ scala
Welcome to Scala 2.12.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_161).
Type in expressions for evaluation. Or try :help.

scala> val inputColumns = List(
 |   List(1, 2, 3, 4, 5, 6),   // first "column"
 |   List(4, 6, 5, 7, 12, 15)  // second "column"
 | )
inputColumns: List[List[Int]] = List(List(1, 2, 3, 4, 5, 6), List(4, 6, 5, 7, 12, 15))

现在,当您在该列表上调用.zipWithIndex时,最终得到List[(List[Int], Int)] - 即元组列表,其中第一个元组类型为List[Int] (列),第二个是Int(索引):

scala> inputColumns.zipWithIndex
res0: List[(List[Int], Int)] = List((List(1, 2, 3, 4, 5, 6),0), (List(4, 6, 5, 7, 12, 15),1))

因此,当您尝试将map函数应用于此列表时,colList[Int]而不是Int,因此col * 2会使毫无意义 - 你将List[Int]乘以2。然后你还试着将列表除以10,显然。

scala> inputColumns.zipWithIndex.map{ case(col, idx) => if(idx == 0) col * 2 else col / 10 }
<console>:13: error: value * is not a member of List[Int]
       inputColumns.zipWithIndex.map{ case(col, idx) => if(idx == 0) col * 2 else col / 10 }
                                                                         ^
<console>:13: error: value / is not a member of List[Int]
       inputColumns.zipWithIndex.map{ case(col, idx) => if(idx == 0) col * 2 else col / 10 }
                                                                                      ^

为了解决这个问题,这取决于你想要实现的目标。如果您想要一个整数列表,然后压缩这些整数以使每个值都有一个关联的索引,那么在调用flatten之前,您应该在inputColumns上调用zipWithIndex。这将导致List[(Int, Int)],其中元组中的第一个值是column值,第二个值是索引。您的地图功能将无需修改即可正常工作:

scala> inputColumns.flatten.zipWithIndex.map{ case(col, idx) => if(idx == 0) col * 2 else col / 10 }
res3: List[Int] = List(2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1)

当然,您不再拥有单独的列。

如果您希望每个列表中的每个值都有关联的索引,则需要先将inputColumns映射到两个压缩列表中,然后使用inputColumns.map(_.zipWithIndex)创建List[List[(Int, Int)]] - 列表(Int, Int)元组列表:

scala> inputColumns.map(_.zipWithIndex)
res4: List[List[(Int, Int)]] = List(List((1,0), (2,1), (3,2), (4,3), (5,4), (6,5)), List((4,0), (6,1), (5,2), (7,3), (12,4), (15,5)))

我们现在可以将原始地图功能应用于zipWithIndex操作的结果:

scala> inputColumns.map(_.zipWithIndex.map { case (col, idx) => if(idx == 0) col * 2 else col / 10 })
res5: List[List[Int]] = List(List(2, 0, 0, 0, 0, 0), List(8, 0, 0, 0, 1, 1))

结果是另一个List[List[Int]],每个内部列表是原始两个输入列上的地图操作的结果。

另一方面,如果idx是列的索引而不是每个值的索引,并且您希望将第一列中的所有值乘以2并将所有值除以其他列中的值为10,那么您需要更改原始map函数以映射每列,如下所示:

scala> inputColumns.zipWithIndex.map {
     |   case (col, idx) => {
     |     if(idx == 0) col.map(_ * 2) // Multiply values in first column by 1
     |     else col.map(_ / 10) // Divide values in all other columns by 10
     |   }
     | }
res5: List[List[Int]] = List(List(2, 4, 6, 8, 10, 12), List(0, 0, 0, 0, 1, 1))

如果您需要进一步澄清,请与我们联系......

<强>更新

case中使用map是一种常见的 Scala 简写。如果高阶函数只接受一个参数,例如:

def someHOF[A, B](x: A => B) = //...

你调用那个函数(用 Scala 术语部分函数 - 一个只包含case语句列表的函数):< / p>

someHOF {
  case expr1 => //...
  case expr2 => //...
  ...
}

然后 Scala 将其视为一种简写:

someHOF {a =>
  a match {
    case expr1 => //...
    case expr2 => //...
    ...
  }
}

或者,稍微简洁一点,

someHOF {
  _ match {
    case expr1 => //...
    case expr2 => //...
    ...
  }
}

例如,对于List,您可以将其与mapflatMapfilter等功能一起使用。

对于map函数,唯一的参数是元组,唯一的case语句用于打开元组并公开其内容。那就是:

val l = List((1, 2), (3, 4), (5, 6))
l.map { case(a, b) => println(s"First is $a, second is $b") }

相当于:

l.map {x =>
  x match {
    case (a, b) => println(s"First is $a, second is $b")
  }
}

两者都会输出:

First is 1, second is 2
First is 3, second is 4
First is 5, second is 6

注意:后者是一个愚蠢的例子,因为map应该将列表中的值映射(即更改)为新列表中的新值。如果您所做的只是打印值,那就更好了:

val l = List((1, 2), (3, 4), (5, 6))
l.foreach { case(a, b) => println(s"First is $a, second is $b") }

答案 1 :(得分:2)

col * 2 col List(1, 2, 3, 4, 5, 6) idx 0 col / 10 inputColumns.zipWithIndex.map{ case (col, idx) => if (idx == 0) col.map(_*2) else col.map(_/10)} match case inputColumns.zipWithIndex.map(x => x._2 match { case 0 => x._1.map(_*2) case _ => x._1.map(_/10) }) },这是不可能的和其他部分import webbrowser webbrowser.open_new('https://google.com') 的情况类似

如果你试图将第一个列表的元素乘以2 并且将列表其余部分的元素除以10 那么你应该做以下事情

{{1}}

即使更好的方法也会使用{{1}} {{1}}

{{1}}