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


1. Scala条件运算符

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

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

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

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

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

2. if 条件判断

  • 在scala中不需要添加分号“;” 作为语句块的结束符
  • 在scala中if else 语句是有返回值的,返回值就是代码块中的最后一行
  • 因为if else 语句是有返回值的,所以可以直接将 if else 语句赋值给一个变量
  • 在scala中无论是方法还是函数 以及条件判断等 返回值都不需要加 return 关键字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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条件语句 可用() 或{},如果条件是多行只能用{}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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() 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

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 循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

/**
* 跳出 嵌套的 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循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/**
* 推导 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 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 循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 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 循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 跳出 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

1
2
3
4
5
6
7
8
9
10
// 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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 方法首先应用于前两个元素,然后再应用于第一次应用的结果和接下去的一个元素,以此类推直至整个列表。例如计算阶乘

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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 方法首先应用于前两个元素,然后再应用于第一次应用的结果和接下去的一个元素,以此类推直至整个列表。将墙面每个结果组成一个集合返回

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

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 /: 和 :\ 的用法

1
2
3
4
5
6
7
8
9
10
11

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 !
评论
  目录