Scala notes finishing (5): functional programming

[TOC]


function passed as value

The test code is as follows:

package cn.xpleaf.bigdata.p4.function

/**
  * scala中关于函数的操作
  */
object _01FunctionOps {
  def main(args: Array[String]): Unit = {
    functionOps1
  }

  /**
    * 作为值传递的函数
    * 将一个函数作为值传递给另外一个函数变量的时候,约定需要在函数后面加上:空格和下划线
    * 相当于数据库中的别名,或者数据库表对应的视图
    */
  def functionOps1: Unit = {
    def sayHi(name:String) = println("Hello, " + name)

    def sayHello = sayHi _

    sayHello("xpleaf")
  }
}

The output is as follows:

Hello, xpleaf

anonymous function

The test code is as follows:

package cn.xpleaf.bigdata.p4.function

/**
  * scala中关于函数的操作
  */
object _01FunctionOps {
  def main(args: Array[String]): Unit = {
    functionOps2
  }

  /**
    * 匿名函数,说白了就是没有函数名字
    *     匿名函数就和java中的匿名内部类一样,是只适合使用一次的函数
    *     一般如果一个函数的参数是一个函数,这种情况下多用匿名函数来作为参数进行传递
    */
  def functionOps2: Unit = {
    val printName = (name:String) => println("你好," + name)
    printName("xpleaf")
  }

}

The output is as follows:

你好,xpleaf

In fact, anonymous functions have been used before when learning ArrayBuffer:

scala> val ab = ArrayBuffer[Int](3, 8, 2, 20, 5, 7)
ab: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(3, 8, 2, 20, 5, 7)
scala> ab.sortWith((v1, v2) => v1 > v2)
res209: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(20, 8, 7, 5, 3, 2)

Functions with function arguments (higher-order functions)

There are two functions of the description (an anonymous function as a parameter and an anonymous function as the return value), please refer to the following test code for details:

package cn.xpleaf.bigdata.p4.function

/**
  * scala中关于函数的操作
  */
object _01FunctionOps {
  def main(args: Array[String]): Unit = {
//    functionOps1
//    functionOps2
    functionOps3
  }

  /**
    * scala的高阶函数,就是函数的 [参数是函数] 的函数,把这种函数称为高阶函数
    */
  def functionOps3: Unit = {

    // 1.匿名函数作为参数
    def highOrderFunc(name:String, func:(String) => Unit): Unit = {
      func(name)
    }

    highOrderFunc("xpleaf", (name:String) => println("Hello, " + name))

    // 2.将匿名函数作为返回值传递给另外一个函数
    def getGoodBayFunction(gMsg: String) = (gName: String) => println(gMsg + ", " + gName)

    val goodbayFunction = getGoodBayFunction("good bye")
    goodbayFunction("xpleaf")

  }
}

The output is as follows:

Hello, xpleaf
good bye, xpleaf

Argument (type) inference

The test code is as follows:

package cn.xpleaf.bigdata.p4.function

import scala.collection.mutable.ArrayBuffer

/**
  * scala中关于函数的操作
  */
object _01FunctionOps {
  def main(args: Array[String]): Unit = {
//    functionOps1
//    functionOps2
//    functionOps3
    functionOps4
  }

  /**
    * 对于匿名函数的省略写法
    */
  def functionOps4: Unit = {
    val ab = ArrayBuffer[Int](1, 2, 3, 4, 5)

    // val newAB = ab.map((x:Int) => x * 100)
    // val newAB = ab.map((x) => x * 100)
    // val newAB = ab.map(x => x * 100)
    val newAB = ab.map(100 * _)
    println(newAB)  // ArrayBuffer(100, 200, 300, 400, 500)

  }
}

The output is as follows:

ArrayBuffer(100, 200, 300, 400, 500)

Common higher-order functions - map function

遍历集合中的每一个元素,返回也是一个集合,集合大小和之前集合相等。
  • Quickly generate numbers like 0.1, 0.2, 0.3, etc.
scala> (1 to 9).map(0.1 * _).foreach(println(_))
0.1
0.2
0.30000000000000004
0.4
0.5
0.6000000000000001
0.7000000000000001
0.8
0.9
  • print triangle
scala> (1 to 9).map("*" * _).foreach(println(_))
*
**
***
****
*****
******
*******
********
*********

Here, we also use foreach, which is similar to map except that its function does not return any value, foreach simply applies the function to each element.

Common higher-order functions - filter function

按照过滤条件,将原集合中不符合条件的数据过滤掉
  • Output all elements that match a certain condition, get all even numbers in a sequence
scala> (1 to 9).filter(line => line % 2 == 0).foreach(println(_))
2
4
6
8

scala> (1 to 9).filter(_ % 2 ==0).foreach(println)
2
4
6
8

Common higher-order functions - reduce functions

scala> (1 to 9).reduce((v1:Int, v2:Int) => v1 + v2)
res4: Int = 45
scala> (1 to 9).reduce(_ + _)
res6: Int = 45
scala> (1 to 9).reduceLeft(_ + _)
res7: Int = 45
scala> (1 to 9).reduceRight(_ + _)
res8: Int = 45

You can write the following function to verify the execution of the reduce function:

scala> val process = (v1:Int, v2:Int) => println(s"v1=${v1}, v2=${v2}")
process: (Int, Int) => Unit = <function2>
scala> def pro(v1:Int, v2:Int):Int = {
     |   println(s"v1=${v1}, v2=${v2}")
     |   v1 + v2
     | }
pro: (v1: Int, v2: Int)Int
  • The execution flow of reduce
scala> (1 to 9).reduce((v1:Int, v2:Int) => pro(v1, v2))
v1=1, v2=2
v1=3, v2=3
v1=6, v2=4
v1=10, v2=5
v1=15, v2=6
v1=21, v2=7
v1=28, v2=8
v1=36, v2=9
res0: Int = 45
  • Execution process of reductLeft
scala> (1 to 9).reduceLeft((v1:Int, v2:Int) => pro(v1, v2))
v1=1, v2=2
v1=3, v2=3
v1=6, v2=4
v1=10, v2=5
v1=15, v2=6
v1=21, v2=7
v1=28, v2=8
v1=36, v2=9
res2: Int = 45
  • Execution process of reductRight
scala> (1 to 9).reduceRight((v1:Int, v2:Int) => pro(v1, v2))
v1=8, v2=9
v1=7, v2=17
v1=6, v2=24
v1=5, v2=30
v1=4, v2=35
v1=3, v2=39
v1=2, v2=42
v1=1, v2=44
res3: Int = 45

In this way, the execution process is very clear. Both reduce and reduceLeft start from the left operand, while reduceRight starts from the right operand.

Common higher-order functions - sortWith function

scala> (1 to 9).sortWith((v1:Int, v2:Int) => v1 > v2).foreach(println(_))
9
8
7
6
5
4
3
2
1

scala> (1 to 9).sortWith(_ > _).foreach(println)
9
8
7
6
5
4
3
2
1

Closure

The variable of the function is not called within its scope, which is the concept of closure, see the following example:

def closePackage: Unit ={
    def mulBy(factor:Double) = (x:Double) => factor * x
    val triple = mulBy(3)
    val half = mulBy(0.5)
    println(triple(14) +" " + half(14)) //42, 7
}

1) The first call of mulBy sets the parameter variable factor to 3,. The variable (x:Double)=&gt;factor *xis referenced within the function body of the function. The function is stored in triple. Then the parameter variable factor is popped from the stack at runtime.

2) mulBy is called again, this time factor is set to 0.5. The variable (x:Double)=&gt;factor *xis referenced in the function body of the function, and the function is stored in half.

Each function is called a closure. Closures consist of code and any non-local variable definitions used by the code.

In fact, the above mulByfunction is similar to the following:

def mulBy1(factor:Double, x:Double) = {
    factor * x
}

I would have liked to write it further like this:

def mulBy2(factor:Double, x:Double) = {
    def work(x:Double) = {
        factor * x
    }
    return work
}

But this way of writing is not supported in scala. The following can be written:

def mulBy2(factor:Double) = {
    (x:Double) => factor * x
}
// 加个return也不行

Closures have been used in Python before. Similar to the above example, Python can be written like this:

def mulBy(factor):
    def work(x):
        return factor * x
    return work

The test is as follows:

>>> def mulBy(factor):
...     def work(x):
...             return factor * x
...     return work
...
>>> triple = mulBy(3)
>>> half = mulBy(0.5)
>>> triple(14)
42
>>> half(14)
7.0

当然,只是Python的语法格式就没有scala那么灵活了。

柯里化(currying函数)

1、柯里化(currying)指的是将原来接受2个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第二个参数作为参数的函数。

2、在函数调用的过程中,就变为了两个函数连续调用的形式。在Spark源码中,也有体现,所以对()()这种形式的Curring函数,一定要掌握。

以下函数接受一个参数,生成另一个接受单个参数的函数,要计算两个数的乘积,调用如下:

/**
    * curryingFunction: 柯里化函数
    */
def curryingFunction ={
    def totalSum(x:Int, y:Int) = println( x + y)

    //totalSum(4,5)

    def totalSumAtTime(x:Int) = (y:Int) => x + y
    println(totalSumAtTime(4)(5))
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324655220&siteId=291194637