我正在研究spark而不是scala专家。我有两个地图功能的变种。你能解释一下它们之间的区别吗?
第一种变体和已知格式。
第一个变种
val.map( (x,y) => x.size())
第二个变体 - >这已经应用于元组
val.map({case (x, y) => y.toString()});
val的类型是RDD[(IntWritable, Text)]
。当我尝试使用第一个函数时,它给出了如下错误。
类型不匹配; 发现:(org.apache.hadoop.io.IntWritable,org.apache.hadoop.io.Text)⇒单位 必需:((org.apache.hadoop.io.IntWritable,org.apache.hadoop.io.Text))⇒单位
当我添加额外的括号时,它说,
无法在方法或函数参数中直接对元组进行解构。
答案 0 :(得分:3)
嗯,你说:
val的类型是RDD [(IntWritable,Text)]
所以它是一个以IntWritable
和Text
为组成部分的arity 2元组。
如果你说
val.map( (x,y) => x.size())
你正在做的是你实际上传递了一个Function2
,一个带有两个参数的函数到map
函数。这将永远不会编译,因为map
想要一个带有一个参数的函数。你能做的是以下几点:
val.map((xy: (IntWritable, Text)) => xy._2.toString)
使用._2
获取以xy
传入的元组的第二部分(类型注释不是必需的,但会更清晰)。
现在是第二个变种(你可以省略外围的那些):
val.map { case (x, y) => y.toString() }
这是一种特殊的scala语法,用于创建一个PartialFunction
语法,该语法在传入以访问x
和y
部分的元组上立即匹配。这是可能的,因为PartialFunction从常规Function1类(Function1[A,B]
可以写成A => B
)扩展为一个参数。
希望更清楚:)
答案 1 :(得分:0)
我在repl中尝试这个:
scala> val l = List(("firstname", "tom"), ("secondname", "kate"))
l: List[(String, String)] = List((firstname,tom), (secondname,kate))
scala> l.map((x, y) => x.size)
<console>:9: error: missing parameter type
Note: The expected type requires a one-argument function accepting a 2-Tuple.
Consider a pattern matching anonymous function, `{ case (x, y) => ... }`
l.map((x, y) => x.size)
也许可以给你一些启发。
答案 2 :(得分:0)
你的第一个例子是一个带有两个参数并返回一个String的函数。这与此示例类似:
scala> val f = (x:Int,y:Int) => x + y
f: (Int, Int) => Int = <function2>
你可以看到f
的类型是(Int,Int) => Int
(只是略微改变了这个以返回int而不是字符串)。这意味着这是一个函数,它接受两个Int作为参数并返回一个Int作为结果。
现在你拥有的第二个例子是用于编写这样的东西的语法糖(快捷方式):
scala> val g = (k: (Int, Int)) => k match { case (x: Int, y: Int) => x + y }
g: ((Int, Int)) => Int = <function1>
您看到函数g
的返回类型现在是((Int, Int)) => Int
。您看得出来差别吗?输入类型g
有两个括号。这表明g
接受一个参数,该参数必须是Tuple[Int,Int]
(或简称为(Int,Int)
)。
回到你的RDD,你拥有的是Tuple[IntWritable, Text]
的集合,所以第二个功能将起作用,而第一个功能将不起作用。