我了解如何在地图中使用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;在斯卡拉?有没有更好的方法来写它?基本上,我想做一个模式匹配,然后对其他参数做一些事情。
答案 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
函数应用于此列表时,col
为List[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
,您可以将其与map
,flatMap
,filter
等功能一起使用。
对于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}}