Scala函数式编程

概念

函数

一种具有名或匿名的操作。其代码直到被调用时才执行。在函数的定义中,可能有也可能没有引用外部的未绑定变量。

def 函数名([参数名: 参数类型],...) [: 返回值类型] = {语句[return] 返回值
}
  1. 函数声明的关键字是 def
  2. [参数名: 参数类型],…:参数列表,如果有必须给出参数类型。多个参数使用逗号分隔。如果没有形参,括号也可以省略
  3. [: 返回值类型] :表示函数的返回值类型,函数可以没有返回值。如果没有返回值,return不生效。只要不是递归函数,就不需要显示指定返回值类型,Scala会自动推断。
  4. 每行语句不用分号";“结束,写上也没错。但是单行包含多条语句,需要使用分号”;"分隔。
  5. return: 返回结果。 不用显示调用return,默认以最后一行结果作为返回值。如果显示的调用了return,则必须指定返回值类型。推荐不显示调用return。
  6. 如果函数明确声明无返回值(声明Unit),那么函数体中即使使用return关键字也不会有返回值

Lambda

一种匿名函数。在它的定义中,可能有也可能没有引用外部的未绑定变量。

闭包

是一个函数,可能匿名或具有名称,在定义中包含了自由变量,函数中包含了环境信息,以绑定其引用的自由变量。

var factor = 2
val mul = (i:Int) => i * factor
(1 to 3).map(mul) // Vector(2,4,6)
factor = 3
(1 to 3).map(mul) // Vector(3,6,9)

factor是一个自由变量,是一个当前作用域中某个值的引用。编译器创建了一个闭包,用于包含mul与它引用的外部变量的上下文信息,从而也就绑定了外部变量本身。所以mul每次调用时都重新读取factor的值。即使factor处于某个局部作用域(如某个方法)中,而我们将mul传递给其他作用域中时,这一机制仍然有效。

函数式编程

  • 函数式编程把函数当做一等公民,充分利用函数,支持的函数的多种使用方式。
  • “函数式编程"是一种"编程范式”(programming paradigm)。它属于"结构化编程"的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用。
  • 函数式编程中,将函数也当做数据类型,因此可以接受函数当作输入(参数)和输出(返回值)。

常见函数式编程

遍历(foreach)

foreach方法可以进行遍历数组

方法签名

foreach(f: (A) => Unit): Unit 

方法解析

foreachAPI说明
参数f:(A) => Unit接收一个函数对象,函数的输入参数为集合的元素,返回值为空
返回值Unit

foreach执行过程

请添加图片描述
示例
有一个列表,包含以下元素1,2,3,4,请使用foreach方法遍历打印每个元素

参考代码

// 定义一个列表
scala> val a = List(1,2,3,4)
a: List[Int] = List(1, 2, 3, 4)
// 迭代打印
scala> a.foreach((x:Int)=>println(x))

映射(map)

map方法接收一个函数,将这个函数应用到每一个元素,返回一个新的列表

方法签名

def map[B](f: (A) ⇒ B): TraversableOnce[B]

方法解析

mapAPI说明
泛型[B]指定map方法最终返回的集合泛型
参数f:(A) => B传入一个函数对象,该函数接收一个类型A(要转换的列表元素),返回值为类型B
返回值TraversableOnce[B]B类型的集合

map执行过程
在这里插入图片描述
示例
有一个列表,包含以下元素1,2,3,4,使用下划线来定义函数,对List中的每一个元素加1

参考代码

scala> val a = List(1,2,3,4)
a: List[Int] = List(1, 2, 3, 4)scala> a.map(_ + 1)

映射扁平化(flatMap)

可以把flatMap,理解为先map,然后再flatten。map是将列表中的元素转换为一个List,flatten再将整个列表进行扁平化。

方法签名

def flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): TraversableOnce[B]

方法解析

mapAPI说明
泛型[B]最终要转换的集合元素类型
参数f:(A) => GenTraversableOnce[B]传入一个函数对象,函数的参数是集合的元素,函数的返回值是一个集合
返回值TraversableOnce[B]B类型的集合

flatMap执行过程
在这里插入图片描述
示例
有一个包含了若干个文本行的列表:“hadoop hive spark flink flume”, “kudu hbase sqoop storm”,获取到文本行中的每一个单词,并将每一个单词都放到列表中

参考代码

scala>  val a = List("hadoop hive spark flink flume", "kudu hbase sqoop storm")
a: List[String] = List(hadoop hive spark flink flume, kudu hbase sqoop storm)scala> a.flatMap(_.split(" "))
res7: List[String] = List(hadoop, hive, spark, flink, flume, kudu, hbase, sqoop, storm)

过滤(filter)

过滤符合一定条件的元素

方法签名

def filter(f: (A)Boolean): TraversableOnce[A]

方法解析

filterAPI说明
参数f:(A) ⇒ Boolean传入一个函数对象,接收一个集合类型的参数,返回布尔类型,满足条件返回true, 不满足返回false

filter执行过程
在这里插入图片描述
示例
有一个数字列表,元素为:1,2,3,4,5,6,7,8,9;请过滤出所有的偶数

参考代码

scala> List(1,2,3,4,5,6,7,8,9).filter(_ % 2 == 0)
res8: List[Int] = List(2, 4, 6, 8)

是否存在(exists)

排序(sorted、sortBy、sortWith)

在scala集合中,可以使用以下几种方式来进行排序

  1. sorted默认排序
  2. sortBy指定字段排序
  3. sortWith自定义排序

默认排序(sorted)

示例
定义一个列表,包含以下元素: 3, 1, 2, 9, 7;对列表进行升序排序

参考代码

scala> List(3,1,2,9,7).sorted
res16: List[Int] = List(1, 2, 3, 7, 9)

指定字段排序 (sortBy)

根据传入的函数转换后,再进行排序

方法签名

def sortBy[B](f: (A) ⇒ B): List[A]

方法解析

sortByAPI说明
泛型[B]按照什么类型来进行排序
参数f: (A) => B传入函数对象,接收一个集合类型的元素参数,返回B类型的元素进行排序
返回值List[A]返回排序后的列表

示例
有一个列表,分别包含几下文本行:“01 hadoop”, “02 flume”, “03 hive”, “04 spark”,请按照单词字母进行排序

参考代码

scala> val a = List("01 hadoop", "02 flume", "03 hive", "04 spark")
a: List[String] = List(01 hadoop, 02 flume, 03 hive, 04 spark)// 获取单词字段
scala> a.sortBy(_.split(" ")(1))
res8: List[String] = List(02 flume, 01 hadoop, 03 hive, 04 spark)

自定义排序 (sortWith)

自定义排序,根据一个函数来进行自定义排序

方法签名

def sortWith(f: (A, A)Boolean): List[A]

方法解析

sortWithAPI说明
参数f: (A, A) ⇒ Boolean传入一个比较大小的函数对象,接收两个集合类型的元素参数,返回两个元素大小,小于返回true,大于返回false
返回值List[A]返回排序后的列表

示例
有一个列表,包含以下元素:2,3,1,6,4,5,使用sortWith对列表进行降序排序

参考代码

scala> val a = List(2,3,1,6,4,5)
a: List[Int] = List(2, 3, 1, 6, 4, 5)// 函数参数只在函数中出现一次,可以使用下划线代替
scala> a.sortWith(_ < _).reverse
res19: List[Int] = List(6, 5, 4, 3, 2, 1)

分组(groupBy)

我们如果要将数据按照分组来进行统计分析,就需要使用到分组方法

方法签名

def groupBy[K](f: (A) ⇒ K): Map[K, List[A]]

方法解析

groupByAPI说明
泛型[K]分组字段的类型
参数f: (A) ⇒ K传入一个函数对象,接收集合元素类型的参数,返回一个K类型的key,这个key会用来进行分组,相同的key放在一组中
返回值Map[K, List[A]]返回一个映射,K为分组字段,List为这个分组字段对应的一组数据

groupBy执行过程
在这里插入图片描述

示例
定义一个元组列表来保存学生姓名和性别 【“张三”, “男”,“李四”, “女”,“王五”, “男”】,按照性别进行分组,将分组后的Map转换为列表:List((“男” -> 2), (“女” -> 1))

参考代码

scala> val a = List("张三"->"男", "李四"->"女", "王五"->"男")
a: List[(String, String)] = List((张三,), (李四,), (王五,))// 按照性别分组
scala> a.groupBy(_._2)
res0: scala.collection.immutable.Map[String,List[(String, String)]] = Map(-> List((张三,), (王五,)),-> List((李四,)))// 将分组后的映射转换为性别/人数元组列表
scala> res0.map(x => x._1 -> x._2.size)
res3: scala.collection.immutable.Map[String,Int] = Map(-> 2,-> 1)

聚合计算(reduce)

聚合操作,可以将一个列表中的数据合并为一个。这种操作经常用来统计分析中

方法签名

def reduce[A1 >: A](f: (A1, A1) ⇒ A1): A1

方法解析

reduceAPI说明
泛型[A1 >: A](下界)A1必须是集合元素类型的子类
参数f: (A1, A1) ⇒ A1传入函数对象,用来不断进行聚合操作,第一个A1类型参数为:当前聚合后的变量,第二个A1类型参数为:当前要进行聚合的元素
返回值A1列表最终聚合为一个元素

reduce执行过程
在这里插入图片描述

  • reduce和reduceLeft效果一致,表示从左到右计算
  • reduceRight表示从右到左计算

示例
定义一个列表,包含以下元素:1,2,3,4,5,6,7,8,9,10, 使用reduce计算所有元素的和

参考代码

scala> val a = List(1,2,3,4,5,6,7,8,9,10)
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)scala> a.reduce((x,y) => x + y)
res5: Int = 55// 第一个下划线表示第一个参数,就是历史的聚合数据结果
// 第二个下划线表示第二个参数,就是当前要聚合的数据元素
scala> a.reduce(_ + _)
res53: Int = 55// 与reduce一样,从左往右计算
scala> a.reduceLeft(_ + _)
res0: Int = 55// 从右往左聚合计算
scala> a.reduceRight(_ + _)
res1: Int = 55

折叠(fold)

fold与reduce很像,但是多了一个指定初始值参数

方法签名

def fold[A1 >: A](z: A1)(f: (A1, A1) ⇒ A1): A1

方法解析

reduceAPI说明
泛型[A1 >: A](下界)A1必须是集合元素类型的子类
参数1z: A1初始值
参数2f: (A1, A1) ⇒ A1传入函数对象,用来不断进行聚合操作,第一个A1类型参数为:当前折叠后的变量,第二个A1类型参数为:当前要进行折叠的元素
返回值A1列表最终折叠为一个元素
  • fold和foldLet效果一致,表示从左往右计算
  • foldRight表示从右往左计算

示例
定义一个列表,包含以下元素:1,2,3,4,5,6,7,8,9,10, 使用fold计算所有元素的和

参考代码

scala> val a = List(1,2,3,4,5,6,7,8,9,10)
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)scala> a.fold(0)(_ + _)
res4: Int = 55

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/89834.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何使用SpringBoot 自定义转换器

&#x1f600;前言 本篇博文是关于SpringBoot 自定义转换器的使用&#xff0c;希望你能够喜欢&#x1f60a; &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大家&#xff0c;您的…

简单谈谈 EMP-SSL:自监督对比学习的一种极简主义风

论文链接&#xff1a;https://arxiv.org/pdf/2304.03977.pdf 代码&#xff1a;https://github.com/tsb0601/EMP-SSL 其他学习链接&#xff1a;突破自监督学习效率极限&#xff01;马毅、LeCun联合发布EMP-SSL&#xff1a;无需花哨trick&#xff0c;30个epoch即可实现SOTA 主要…

Vue3 setup tsx 子组件向父组件传值 emit

需求&#xff1a;Vue3 setup 父组件向子组件传值&#xff0c;子组件接收父组件传入的值&#xff1b;子组件向父组件传值&#xff0c;父组件接收的子组件传递的值。 父组件&#xff1a;parent.tsx&#xff1a; import { defineComponent, ref, reactive } from vue; import To…

【STM32】利用CubeMX对FreeRTOS用按键控制任务

对于FreeRTOS中的操作&#xff0c;最常用的就是创建、删除、暂停和恢复任务。 此次实验目标&#xff1a; 1.创建任务一&#xff1a;LED1每间隔1秒闪烁一次&#xff0c;并通过串口打印 2.创建任务二&#xff1a;LED2每间隔0.5秒闪烁一次&#xff0c;并通过串口打印 3.创建任…

【工作记录】mysql中实现分组统计的三种方式

前言 实际工作中对范围分组统计的需求还是相对普遍的&#xff0c;本文记录下在mysql中通过函数和sql完成分组统计的实现过程。 数据及期望 比如我们获取到了豆瓣电影top250&#xff0c;现在想知道各个分数段的电影总数. 表数据如下: 期望结果: 实现方案 主要思路是根据s…

SpringMVC拦截器

1.拦截器简介 拦截器&#xff08;Interceptor&#xff09;是一种动态拦截方法调用的机制&#xff0c;在SpringMVC中动态拦截控制器方法的执行 作用: 在指定的方法调用前后执行预先设定的代码 阻止原始方法的执行 总结&#xff1a;拦截器就是用来做增强 看完以后&#xff0…

【在一个升序数组中插入一个数仍升序输出】

在一个升序数组中插入一个数仍升序输出 题目举例&#xff1a; 有一个升序数组nums&#xff0c;给一个数字data&#xff0c;将data插入数组nums中仍旧保证nums升序&#xff0c;返回数组中有效元素个数。 比如&#xff1a;nums[100] {1, 2, 3, 5, 6, 7, 8, 9} size 8 data 4 …

elementUi表单恢复至初始状态并不触发表单验证

elementUi表单恢复至初始状态并不触发表单验证 1.场景再现2.解决方法 1.场景再现 左侧是树形列表&#xff0c;右侧是显示节点的详情&#xff0c;点击按钮应该就是新增一个规则的意思&#xff0c;表单内容是没有改变的&#xff0c;所以就把需要把表单恢复至初始状态并不触发表单…

正则表达式试炼

序 我希望在这里列出我很多想写的正则表达式&#xff0c;很多我想写&#xff0c;但是不知道怎么写的。分享点滴案例。未来这个文章会越来越长 前言 互联网时代&#xff0c;除了文本还有更好的学习方式&#xff0c;下面是几个不错的练习网站&#xff0c;如果你想系统地学习&a…

深入了解Linux运维的重要性与最佳实践

Linux作为开源操作系统的代表&#xff0c;在企业级环境中的应用越来越广泛。而在保障Linux系统的正常运行和管理方面&#xff0c;Linux运维显得尤为关键。本文将介绍Linux运维的重要性以及一些最佳实践&#xff0c;帮助读者更好地了解和掌握Linux系统的运维技巧。 首先&#xf…

如何更快地执行 Selenium 测试用例?

前言&#xff1a; 当我们谈论自动化时&#xff0c;首先想到的工具之一是 Selenium。我们都知道Selenium WebDriver 是一个出色的 Web 自动化工具。实施Selenium 自动化测试的主要原因是加速 selenium 测试。在大多数情况下&#xff0c;Selenium 的性能比手动的要好得多。但是&…

离线安装vscode插件,导出 Visual Studio Code 的扩展应用,并离线安装

在没有网络的情况下&#xff0c;如何安装vscode插件 1.使用之前电脑安装过的插件包 Visual Studio Code 的扩展应用安装位置在文件夹 .vscode/extensions 下。不同平台&#xff0c;它位于&#xff1a; Windows %USERPROFILE%\.vscode\extensions Mac ~/.vscode/extensions L…

C字符串练习题(6.3.1)

编写一个程序&#xff0c;从键盘上读入一个小于1000的正整数&#xff0c;然后创建并输出一个字符串&#xff0c;说明该整数的值。例如&#xff0c;输入941&#xff0c;程序产生的字符串是“Nine hundred and forty one”。 #include<stdlib.h> #include<string.h>…

【JAVA】我们常常谈到的方法是指什么?

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️初识JAVA】 文章目录 前言方法方法的分类方法的定义方法调用方法重载 前言 在之前的文章中我们总是会介绍到类中的各式各样的方法&#xff0c;也许在应用中我们对它已经有了初步的了解&#xff0c;今…

# ⛳ Docker 安装、配置和详细使用教程-Win10专业版

目录 ⛳ Docker 安装、配置和详细使用教程-Win10专业版&#x1f69c; 一、win10 系统配置&#x1f3a8; 二、Docker下载和安装&#x1f3ed; 三、Docker配置&#x1f389; 四、Docker入门使用 ⛳ Docker 安装、配置和详细使用教程-Win10专业版 &#x1f69c; 一、win10 系统配…

使用docker快速搭建wordpress服务,并指定域名访问

文章目录 引入使用docker快速跑起服务创建数据库安装wordpress服务配置域名 引入 wordpress是一个基于PHP语言编写的开源的内容管理系统&#xff08;CMS&#xff09;&#xff0c;它有丰富的插件和主题&#xff0c;可以非常简单的创建各种类型的网站&#xff0c;包括企业网站、…

vuejs 设计与实现 - 渲染器 - 挂载与更新

渲染器的核心功能:挂载与更新 1.挂载子节点和元素的属性 1.2挂载子节点 (vnode.children) vnode.children可以是字符串类型的&#xff0c;也可以是数组类型的&#xff0c;如下&#xff1a; const vnode {type: div,children: [{type: p,children: hello}] } 可以看到&#…

【前端|Javascript第4篇】详解Javascript的事件模型:小白也能轻松搞懂!

前言 在当今数字时代&#xff0c;前端技术正日益成为塑造用户体验的关键。而其中一个不可或缺的核心概念就是JavaScript的事件模型。或许你是刚踏入前端领域的小白&#xff0c;或者是希望深入了解事件模型的开发者&#xff0c;不论你的经验如何&#xff0c;本篇博客都将带你揭开…

聚类与回归

聚类 聚类属于非监督式学习&#xff08;无监督学习&#xff09;&#xff0c;往往不知道因变量。 通过观察学习&#xff0c;将数据分割成多个簇。 回归 回归属于监督式学习&#xff08;有监督学习&#xff09;&#xff0c;知道因变量。 通过有标签样本的学习分类器 聚类和…

SpringCloud中 Sentinel 限流的使用

引入依赖 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>手动编写限流规则&#xff0c;缺点是不够灵活&#xff0c;如果需要改变限流规则需要修改源码…