【scala系列】4、流程控制、循环介绍


1. Scala条件运算符

运算符 操作 描述
&& 运算符左侧和右侧的值为true。仅当左侧为真时,右侧才被计算。
|| 左侧或右侧的至少一个值为true。仅当左边为假时才计算右侧。
> 大于 左侧的值大于右侧的值。
>= 大于或等于 左侧的值大于或等于右侧的值。
< 少于 左侧的值小于右侧的值。
<= 小于或等于 左侧的值小于或等于右侧的值
== 等于 左侧的值与右侧的值相同。
!= 不等于 左侧的值与右侧的值不同。

&& 和 || 是“短路”运算符。 一旦知道答案,他们就停止计算表达式。

在Java中,==仅比较对象引用。它不会执行逻辑等同性检查,即比较字段值。使用 equals 方法。

Scala使用==作为逻辑等式,但它调用equals方法。

当您想要比较引用,但不测试逻辑时,可以使用新的方法 eq。

2. if 条件判断

  • 在scala中不需要添加分号“;” 作为语句块的结束符
  • 在scala中if else 语句是有返回值的,返回值就是代码块中的最后一行
  • 因为if else 语句是有返回值的,所以可以直接将 if else 语句赋值给一个变量
  • 在scala中无论是方法还是函数 以及条件判断等 返回值都不需要加 return 关键字
object IfDemo {
  def main(args: Array[String]): Unit = {
    val num = 21

    val name = if (num > 20) "小明" else "小红"

    print("name=>" + name)

    // 如果在if else语句中 返回值的类型是不一样,scala会自动推断两者的公共类型,作为变量类型

    //Any
    val name2 = if (num == 20) "小明" else 99

    println("name2=>" + name2)
    println("name2.getClass=>" + name2.getClass)

    //如果if else  语句中缺少了else语句块,那么其实默认是Unit ,Unit 用“()”表示 ,类似于java中的void
    val name3 = if (num > 20) "小明"
    val name4 = if (num > 20) "小明" else ()

    print(name3)
    print(name4)
  }
}

3. for 循环

scala中并没有Java中常见的 ** for(int i = 0;i<100;i+) ** 这种for循环方式

Scala中会使用to方法会产生一个连续不远的区间范围 [0-10] 的方式(to 两边都包含)

for条件语句 可用() 或{},如果条件是多行只能用{}

def main(args: Array[String]): Unit = {

    //使用to方法会产生一个连续不远的区间范围 [0-10] 两边都包含
    for (i <- 0 to 10) {
      println("i=>" + i) // 0 - 10
    }

    //使用until方法会产生一个连续不远的区间范围 [0-10) 不包含10
    for (i <- 0 until 10) {
      println("i=>" + i) //  0 - 9
    }

    //遍历字符串
    for (s <- "xiaoming") {
      println(s)
    }

    //多重for循环 类似 for(i <- 1 to 9){for(j <- 1 to 9){println(i+"*"+j+"="+i*j)}}
    for (i <- 1 to 9; j <- 1 to 9) {
      println(i + "*" + j + "=" + i * j) //1*1=1...9*9=81
    }

    //for 循环后可以加守卫条件
    for (i <- 1 to 10 if (i % 2) == 0) println("i=" + i) // i = 2,4,6,8,10

    //遍历数组

    val arr2 = Array(1, true, "xioam")
    for (a <- arr2) {
      println(a)
    }

  }

3.1 跳出for循环

scala 中并没有break 关键字, 但是提供了break() 方法


import scala.util.control.Breaks._

    breakable {
      for (a <- 1 to 10) {
        if (a <= 5) {
          println("a in break =" + a)
        } else {
          break()
        }
      }
    }

    /**
      * a in break =1
      * a in break =2
      * a in break =3
      * a in break =4
      * a in break =5
      */

3.2 跳出嵌套 for 循环


  /**
   * 跳出 嵌套的 for 循环
   */
  def forBreak2(): Unit = {
    //scala 中并没有break 关键字, 但是提供了break() 方法
    val b1 = new Breaks
    val b2 = new Breaks

    b1.breakable{
      for (i <- 1 to 5) {
        b2.breakable{
          for(j <- 1 to 3){
            if(j >2){
              b2.break()
            }
            println(s"i=$i,j=$j")
          }
        }

        if(i >=3 ){
          b1.break()
        }
      }
    }

    /**
     * i=1,j=1
     * i=1,j=2
     * i=2,j=1
     * i=2,j=2
     * i=3,j=1
     * i=3,j=2
     */
  }

3.3 推导式for循环

/**
    * 推导 for 循环
    */
  def forYield(): Unit = {

    //推导式for循环
    val arr = for (i <- 1 to 5) yield i * 2

    println(arr) // Vector(2, 4, 6, 8, 10)

    val a = for (i <- 1 to 5) yield i //什么也没做相当于复制了一遍 for 循环中的元素
    println(a) //Vector(1, 2, 3, 4, 5)

    val b = for (i <- 1 to 5) yield i * 2 //对for循环中的每个元素 乘以2
    println(b) //Vector(2, 4, 6, 8, 10)

    val c = for (i <- 1 to 5) yield i % 2 //对for循环中的每个元素取模
    println(c) //Vector(1, 0, 1, 0, 1)

    //Scala 数组上的 for 循环 yield 的例子

    val d = Array(1, 2, 3, 4, 5)
    for (e <- d) yield e //相当于复制了d 数组

    for (e <- d) yield e * 2 //对d 数组中每个元素 乘以 2

    for (e <- d) yield e % 2 //对d 数组中的每个元素取模

    //yield 还可以跟守卫条件一起用

    for (e <- d if e > 2) yield e

    //res1: Array[Int] = Array(3, 4, 5) //如上, 加上了 "if e > 2" 作为守卫条件用以限制得到了只包含了三个元素的数组.


    for (i <- 1 to 3; j = i * i) println(j) // 1,4,9

    val f1 = for (n <- List(1, 2, 3, 4) if n % 2 == 1) yield n * n
    println(f1) // List(1, 9) 

    //等价于

    val f2 = List(1, 2, 3, 4).filter(_ % 2 == 1).map(n => n * n)
    println(f2) // Array(1, 9)

    //等价于
    val f3 = for (n <- Array(1, 2, 3, 4) if n % 2 == 1) yield n * n
    println(f3.foreach(println(_))) // 1 , 9

    //注意:如果if后面不止一条语句,要用{..}包裹。

    val f4 = for (i <- 0 to 2; j <- 0 to 2) yield i + j
    println(f4) //Vector(0, 1, 2, 1, 2, 3, 2, 3, 4)

    val f5 = for {i <- 0 to 2; j <- 0 to 2} yield i + j
    println(f5) //Vector(0, 1, 2, 1, 2, 3, 2, 3, 4)

    println(triangle(15)) //Vector((3,4,5), (5,12,13), (6,8,10), (9,12,15))
  }

  /**
    * 最长边在 n 以内所有符合勾股弦的三角形
    * @param n
    * @return
    */
  def triangle(n: Int) = {
    for { x <- 1 to n
          y <- x to n
          z <- y to n
          if (x * x + y * y == z * z)
    } yield (x, y, z)
  }

3.4 yield 关键字

如果你熟悉scala的loop结构,就会知道在for 后的圆括号可以做许多事情,你可以加入if 表达式或者其他语句

  • 针对每一次for循环的迭代,yield会产生一个值,被循环记录下来(内部实现上,像是一个缓冲区)
  • 当循环结束后,会返回所有yield的值组成的集合
  • 返回集合的类型与被遍历的集合类型是一致的
  • for (e<-List(1,2,3)) { yield e*e } // 语法错误,yield不能在任何括号内

4. while 循环

4.1 while

 // while ...
    var i = 0
    while ( i <= 3) {
      println("i=>" + i)
      i += 1
    }
    /**
      * i=>0
      * i=>1
      * i=>2
      * i=>3
      */


    // 2.修改标志位跳出while循环
    var j = 0
    var flag = true

    while ( flag ) {
      println("j=>" + j)
      j += 1
      if ( j == 3) flag = false
    }

    /**
      * j=>0
      * j=>1
      * j=>2
      */

4.2 do…while 循环

 /**
    *  do.. while...
    */
  def doWhile(): Unit = {
    var k = 1
    do {
      println("k=>" + k)
      k += 1
    } while (k <= 3)

    /**
      * k=>1
      * k=>2
      * k=>3
      */
  }

4.3 跳出 while 循环

/**
    * 跳出 while 循环
    */
  def whileBreak(): Unit = {
    // 跳出while循环
    import scala.util.control.Breaks._
    // 1.使用break 跳出
    var q = 1
    breakable {
      while (true) {
        println("q=>" + q)
        q += 1
        if (q == 3) break()
      }
    }

    /**
      * q=>1
      * q=>2
      * q=>3
      */
  }

5. foreach

    // to包含,until不包含(最后的数)
    List(1,2,3).foreach(println) // 1,2,3
    //也可以写成:
    (1 to 3).foreach(println) // 1,2,3
    //或者
    (1 until 4) foreach println // 1,2,3
    //或者
    Range(1,4) foreach println // 1,2,3
    //或者
    Range(1,4).foreach(println(_)) // 1,2,3

6. forall

  • 所有都符合返回true 否则false。
  • 相当于 A1 && A2 && A3 && … && Ai && … && An
object ForallDemo {
  def main(args: Array[String]): Unit = {
    //判断如果每个数都大于0 返回true,否则返回false
    val f1 = (1 to 3) forall (0 < _)
    println(f1) // true

    val f2 = (-1 to 3) forall (0 < _)
    println(f2) // false

    for (i <- 1 to 10 if isPrime(i)) {
      println(s"质数有:$i")
    }

    val f3 = (2 to 20) partition (isPrime _)
    println(f3) // (Vector(2, 3, 5, 7, 11, 13, 17, 19),Vector(4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20))
    println(f3._1) // Vector(2, 3, 5, 7, 11, 13, 17, 19)
    println(f3._2) // Vector(4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20)

  }

  /**
    * 判断质数
    * @param n
    * @return
    */
  def isPrime(n: Int) = {
    2 until n forall (n % _ != 0)
    // 2 until n forall (n % _ != 0)
    // 生成从2 到 n-1 的区间,用n 对这个区间的所有数取模,所有都不为0 则为奇数,返回true,否则返回false
  }
}

7. reduceLeft

reduceLeft 方法首先应用于前两个元素,然后再应用于第一次应用的结果和接下去的一个元素,以此类推直至整个列表。例如计算阶乘

object ReduceLeftDemo {
  def main(args: Array[String]): Unit = {
    val l1 =List(1,4,9,6,7)

    // 去最大值
    val m1 = l1.reduceLeft( (x,y)=> if (x>y) x else y )
    println(m1) // 9
    // 或者简化为:
    val m2 = l1.reduceLeft(_ max _)
    println(m2) // 9
    //相当于:
    val m3 = ((((1 max 4) max 9) max 6) max 7)
    println(m3) // 9

    //计算 累加值
    val sum1 = l1.reduceLeft(_+_)
    println(sum1) //27
    //相当于:
    val sum2 = ((((1 + 4) + 9) + 6) + 7)
    println(sum2) // 27

    // 计算阶乘
    val fac1 = fac(5) //
    println(fac1) //120
    //相当于:5*4*3*2 = 120
    val fac2 = ((((1*2)*3)*4)*5)
    println(fac2) //120
  }

  /**
    * 计算阶乘
    * @param n
    * @return
    */
  def fac(n: Int) = {
    1 to n reduceLeft(_*_)
  }
}

8. foldLeft

object FoldLeftDemo {
  def main(args: Array[String]): Unit = {

    val s0 = sum0(List(1,3,5,7))
    println(s0) // 16

    val s1 = sum1(List(1,3,5,7))
    println(s1) // 16

    val s2 = sum2(List(1,3,5,7))
    println(s2) // 16

    val s3 = sum3(List(1,3,5,7))
    println(s3) // 16

    //乘法
    val m1 = multiply(Seq(1,2,3,4,5))
    println(m1) //120

    multiply(1 until 5+1) // 120
  }

  /**
    * 阶乘
    * @param L
    * @return
    */
  def multiply(L: Seq[Int]) = L.foldLeft(1)(_ * _)

  /**
    * 累加 将传过来的集合 + 10
    * @param L
    * @return
    */
  def sum1(L: Seq[Int]) = {
    L.foldLeft(10)((a, b) => {
      println(s"a=$a,b=$b")
      a + b
    })

    /**
      * a=10,b=1
      * a=11,b=3
      * a=14,b=5
      * a=19,b=7
      */
  }

  def sum2(L: Seq[Int]) = {
    L.foldLeft(2)(_ + _)
  }

  def sum3(L: List[Int]) = {
    (3/:L){_ + _}
  }
  /**
    * 计算累加
    * @param list
    * @return
    */
  def sum0(list: List[Int]): Int = {
    var result = 0
    for (l <- list)
      result += l
    result
  }
}

9. scanLeft

reduceLeft 方法首先应用于前两个元素,然后再应用于第一次应用的结果和接下去的一个元素,以此类推直至整个列表。将墙面每个结果组成一个集合返回


object ScanLeftDemo {

  def main(args: Array[String]): Unit = {

    val list = List(1, 2, 3, 4, 5)

    val l1 = list.scanLeft(0)(_ + _) // (0,1,3,6,10,15)
    println(l1) // List(0, 1, 3, 6, 10, 15)
    //相当于:
    (0, (0 + 1), (0 + 1 + 2), (0 + 1 + 2 + 3), (0 + 1 + 2 + 3 + 4), (0 + 1 + 2 + 3 + 4 + 5))

    //val l2 = list.scanLeft(1)(_*_)
    val l2 = list.scanLeft(1) {_ * _}
    println(l2) //List(1, 1, 2, 6, 24, 120)
    //相当于
    (1, 1*1, 1*1*2, 1*1*2*3, 1*1*2*3*4, 1*1*2*3*4*5)
  }
}

9.1 /: 和 :\ 的用法


    val s1 = (2 /: List(1,2, 3))(_*_)
    println(s1) // 12 相当于 ((( 2 * 1 ) *  2 ) * 3 )

    val s2 = ( List(1,2, 3) :\ 1)(_+_)
    println(s2) // 7 相当于 (1 + (2 + (3 + 1)))

    // 简单来说:加法用0,乘法用1
    // (z /: List(a, b, c)) (op) 相当于 op(op(op(z, a), b), c)
    // (List(a, b, c) :\ z) (op) equals op(a, op(b, op(c, z)))

文章作者: hnbian
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 hnbian !
评论
 上一篇
【scala系列】5、容器类型:Array、List、Range 【scala系列】5、容器类型:Array、List、Range
1. 可变集合与不可变集合这里的可变与不可变不是说集合中的值是否改变而是指该对象在内存中的引用是否改变,如下代码所示: //Array 不可变即使修改某个元素,对象hashcode 仍然不会改变 var arr1 = Arr
2020-03-25
下一篇 
【scala系列】3、变量/常量的定义,操作符介绍 【scala系列】3、变量/常量的定义,操作符介绍
1. 变量定义在scala中定义变量有两个关键字:val、var val:不可变的,即不可再次给其赋值,类似于java中被final修饰的常量 var: 可变的,即可以再次给他赋值 声明变量的通用格式 关键字变量名:变量的类型=变量
2020-03-18
  目录