热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Scala的相关知识(二)——函数、数组

在Scala中定义函数时,需要定义函数的函数名,参数,函数体。先写一个函数如下所示:--单行的函数:defsayHello(name:String)pr

  在Scala中定义函数时,需要定义函数的函数名,参数,函数体。

先写一个函数如下所示:

    

 -- 单行的函数 : def sayHello(name:String) =print("Hello,"+name)
   如果函数体中有多行代码,则可以使用代码块的方式包裹多行代码,代码块中最后一行的返回值就是整个函数的返回值。与java中不同,不是使用return返回值的。注意:一定要有等号,才会有返回值。
    比如如下函数:   实现累加的功能。

 def sum(n:Int)={
      var sum=0 
      for(i <- 1 to n) sum+=i
      sum    // 函数的返回值 
    }

-- 递归函数 :  如果在函数体内递归调用函数自身,则必须手动给出函数的返回类型。 

  eg :实现经典的斐波那契数列: 

  

 -- 函数的默认参数

    在Scala中,有时候我们调用某些函数时,不希望给出参数的具体值,而希望使用参数自身默认的值, 此时就可以在定义函数时使用默认参数。如果给出的参数不够,则会从左往右依次应用参数,如果调用函数时,给出了参数,就是用实际值代替默认参数。


-- 带名参数

  在调用函数时,也可以不按照函数定义的参数顺序来传递参数,而是使用带名参数的方式来传递。还可以混合使用未命名参数和带名参数,但是未命名参数必须排在带名参数的前面。


-- 变长参数 : 有时我们需要将函数定义为参数个数可变的形式,此时可以使用变长参数定义函数


-- 使用序列调用变长参数 
  如果想要将一个 已有的序列直接调用变长参数函数,是不对的,比如,val s=sum(1 to 5) , 此时需要使用Scala特殊的语法将参数定义为序列,让Scala解释器能够识别,这种语法非常有用!一定要好好注意,在spark的源码中大量地使用到了。

  eg:  val s=sum(1 to 5 :_*) 

 // 案例: 使用递归函数实现累加
    def sum2(nums:Int*):Int ={
      if(nums.length ==0) 0
      else nums.head +sum2(nums.tail:_*)
    }
-- 过程 :  定义函数时,如果函数体直接包裹在了花括号里面,而没有使用=连接,则函数的返回值类型就是Unit ,这样的函数就被称之为 过程。过程通常用于不需要返回值的函数。 过程还有一种写法,就是将函数的返回值类型定义为Unit 
  def sayHello(name:String)="Hello," +name
  def sayHello(name:String) {print("Hello, "+name);"Hello, "+ name}

  def sayHello(name :String):Unit="Hello, "+name 

-- lazy值 : 在Scala中,提供了lazy值得特性,如果将一个变量声明为lazy,则只有第一次使用该变量的时候,变量对应的表达式才会发生计算。这种特性对于特别耗时的计算操作特别有用,比如打开文件进行IO,进行网络IO等。

import scala.io.Source._
 lazy val lines=fromFile("C://Users//Administrator//Desktop//test.txt").mkString 
//,即使文件不存在,也不会报错,只有第一个使用变量时会报错,证明了表达式计算的lazy特性。
-- 异常:在Scala中,异常处理和捕获机制与Java是非常相似的。
try{
    throw new IllegalArgumentException("x should not be negative")
  } catch{
    case _:IllegalArgumentException =>println("Illegal Argument") // 
  }finally{
    print("release resources!")
  }
 -- 数组操作之Array、ArrayBuffer以及遍历数组
  在Scala中,Array代表的含义与java类似 ,也是长度不可改变的数组。此外,由于Scala与Java都是运行在JVM中,双方可以相互调用,因此Scala数组的底层实际上是Java数组。例如字符串数组在底层就是Java的String[],整数数组在底层就是Java的Int[] 

 数组初始化之后,长度就固定下来了,而且元素全部根据其类型初始化 

val a=new Array[Int](10)
a[0] =1    // 赋值  
val a=new Array[String](10)

可以直接使用Array()创建数组,元素类型自动推断  

val a =Array("hello","World")
a[0] ="hi"
  --  ArrayBuffer : 在Scala中,如果需要类似于java中的ArrayList这种长度可变的集合类,则可以使用ArrayBuffer
   // 如果不想每次都使用全限定名,则可以预先导入ArrayBuffer类,
    import scala.collection.mutable.ArrayBuffer
   // 使用ArrayBuffer()的方式可以创建一个空的 ArrayBuffer
    val b =ArrayBuffer[Int]() 
   // 使用 += 操作符 ,可以添加一个元素,或者多个元素
   b+= 1     b+=(2,3,4,5)
   // 使用 ++=操作符 ,可以添加其他集合中的所有元素
   b++= Array(6,7,8,9,10)
   // 使用trimEnd()函数,可以从尾部截断指定个数的元素
   b.trimEnd(5)
   // 使用insert()函数可以在指定的位置上插入元素(效率太低,因为要移动指定位置后的所有元素)
    b.insert(5,6)  //在index为5的位置上插入 元素6
    b.insert(6,7,8,9,10)  // 插入多个元素
   // 使用remove() 函数可以移除指定位置的元素
   b.remove(1)    b.remove(1,3)
   // Array 与ArrayBuffer可以相互进行转换
   b.toArray

   b.toBuffer

 相关代码展示如下:



-- 遍历Array和ArrayBuffer 

// 使用for循环 和until遍历Array/ArrayBuffer
    // until是RichInt提供的函数
 for(i <- 0 until b.length) print(b(i) + " ")
      // 跳跃遍历Array/ArrayBuffer
    for(i <- 0 until(b.length,2)) print(b(i) +" ")
        // 从尾部遍历 Array /ArrayBuffer
    for(i <- (0 until b.length).reverse) print(b(i)+" ")
         // 使用 增强型for循环, 遍历 Array/ArrayBuffer
    for(e <- b) print(e+ " ")

-- 数组常见操作

val a =Array(9,5,7,8,3)
     // 数组元素求和
     val sum =a.sum
     //获取数组最大值
     val max =a.max
     // 对数组进行排序
     scala.util.Sorting.quickSort(a)
     // 获取数组中所有元素内容
     a.mkString    a.mkString(",") a.mkString("<",",",">")
     // toString函数
     a.toString()   b.toString() 

代码展示如下所示:

-- 使用yield 和函数式编程对数组进行转换

 val c=Array(1,2,3,4,5)
  // 对Array进行转换, 获取的还是Array
  val c2= for( ele <- c2) yield ele *ele
  val d=ArrayBuffer[Int]()
  d+=(1,2,3,4,5)
  val d2= for(ele <- d)yield ele * ele

  //结合if守卫 ,仅转换需要的元素
  val c3  =for(ele <- c if ele %2 ==0)yield ele *ele
  // 使用函数式编程转换数组(通常使用第一种方式)
  c.filter(_ % 2 ==0).map(_ * 2)  // 筛选c中的偶数,并进行乘2操作
  c.filter{_ % 2==0}.map{}

相关代码展示如下:


--------   算法案例 :移除第一个负数之后的所有负数 ------

// 构建数组  
   val a=ArrayBuffer[Int]() 
    a+=(1,2,3,4,5,-1,-5,-3,-9)
    // 每发现一个第一个负数之后的负数,就进行移除,性能较差,多次移动数组
    var foundFirstNegative=false;
    var arrayLength=a.length ;
    var index= 0
    while(index = 0)
        index +=1
      else {
        if(!foundFirstNegative){foundFirstNegative=true;index+=1}
        else {a.remove(index);arrayLength -=1}
      }

由于性能较差,对其进行改良,改良版如下:

 // 重新构建数组
     val a=ArrayBuffer[Int]()
     a += (1,2,3,4,5,-1,-3,-5,-9)
      // 每记录所有不需要移除的元素的索引,稍后一次性移除所有需要移除的元素
      // 性能较高,数组内的元素迁移只要执行一次即可。
     var foundFirstNegative=false;
     val keepIndexes=for(i <- until a.length if!foundFirstNegative || a(i) >=0 )yield{
        if(a(i) <0) foundFirstNegative=true
        i
      } 
     for(i <- 0 until keepIndexes.length ){a(i)=a(keepIndexes(i))}
     a.trimEnd(a.length-keepIndexes.length)


推荐阅读
  • 第四章高阶函数(参数传递、高阶函数、lambda表达式)(python进阶)的讲解和应用
    本文主要讲解了第四章高阶函数(参数传递、高阶函数、lambda表达式)的相关知识,包括函数参数传递机制和赋值机制、引用传递的概念和应用、默认参数的定义和使用等内容。同时介绍了高阶函数和lambda表达式的概念,并给出了一些实例代码进行演示。对于想要进一步提升python编程能力的读者来说,本文将是一个不错的学习资料。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 也就是|小窗_卷积的特征提取与参数计算
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了卷积的特征提取与参数计算相关的知识,希望对你有一定的参考价值。Dense和Conv2D根本区别在于,Den ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 摘要: 在测试数据中,生成中文姓名是一个常见的需求。本文介绍了使用C#编写的随机生成中文姓名的方法,并分享了相关代码。作者欢迎读者提出意见和建议。 ... [详细]
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
  • Python SQLAlchemy库的使用方法详解
    本文详细介绍了Python中使用SQLAlchemy库的方法。首先对SQLAlchemy进行了简介,包括其定义、适用的数据库类型等。然后讨论了SQLAlchemy提供的两种主要使用模式,即SQL表达式语言和ORM。针对不同的需求,给出了选择哪种模式的建议。最后,介绍了连接数据库的方法,包括创建SQLAlchemy引擎和执行SQL语句的接口。 ... [详细]
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
author-avatar
手机用户2502924457
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有