justtreee / blog

31 stars 8 forks source link

【Scala学习笔记 · 二】映射和元组、类、对象 #7

Open justtreee opened 6 years ago

justtreee commented 6 years ago

第四章 映射和元组

1. 映射

Scala中映射是对偶的集合,也就是两个值构成的组,这两个值不一定是一个类型的。

//建立映射的两种方式
val sc = Map("A"->99, "B"-> 80)
val sc2 = Map(("Alice",10), ("Bob",8)) 

//获取映射的值
val Asc = sc.get("A")
//Asc: Option[Int] = Some(99)
val Bobsc = sc2.getOrElse("Bob",0)
//如果映射包含键“Bob”,返回相应值,否则返回0
//Bobsc: Int = 8

//映射的更新
val newsc = sc+("C"->88, "D"->77)

//映射迭代之键值交换
for((k, v) <- sc) yield (v,k)
//res0: scala.collection.immutable.Map[Int,String] = Map(99 -> A, 80 -> B)

2. 元组

映射是对偶的集合,对偶是元组(tuple)的最简单形式——元组是不同类型的值的聚集。

//创建一个元组
val t = (1,2.2,"sadf")
//t: (Int, Double, String) = (1,2.2,sadf)

//如下方法访问组元,这里将第二个组元传给变量second
val second = t._2
//second: Double = 2.2

//也可以一起访问并赋值
val (fir, sec, thi) = t
//fir: Int = 1
//sec: Double = 2.2
//thi: String = sadf

//当然也可以不全部获取
val (fir1, sec1, _) = t
//fir1: Int = 1
//sec1: Double = 2.2

拉链操作

val symbol = Array("<", "-", ">")
val count = Array(2, 10, 2)
val pairs = symbol.zip(count)

//pairs: Array[(String, Int)] = Array((<,2), (-,10), (>,2))

练习

  1. 设置一个映射,其中包含你想要的一些装备,以及它们的价格。然后构建另一个映射,采用同一组键,但在价格上打9折。
val p :Map[String, Int] = Map("t1"->10, "t2"->12, "t3"->20)
val ans = (for((k, v) <- p) yield {(k,v*0.9)})

//p: Map[String,Int] = Map(t1 -> 10, t2 -> 12, t3 -> 20)
//ans: scala.collection.immutable.Map[String,Double] = Map(t1 -> 9.0, t2 -> 10.8, t3 -> 18.0)
  1. 编写一段程序,从文件中读取单词。用一个可变映射来清点每一个单词出现的频率。
    
    import java.io.File
    import java.util.Scanner

val in = new Scanner(new File("/text.txt")) val map = new scala.collection.mutable.HashMap[String, Int]() while(in.hasNext()){ val str = in.next() map(str) = map.getOrElse(str,0) + 1 } println(map.mkString(","))

//(alpha) -> 1,PageRank -> 1,Collaborative -> 1 .......................


3. 重复前一个练习,这次用不可变的映射。
```scala
import java.io.File
import java.util.Scanner

val in = new Scanner(new File("C:/Users/67329/Desktop/text.txt"))
val map = Map[String, Int]()
var m = map //不可变(val)映射
while(in.hasNext()){
  val str = in.next()
  m += (str -> (m.getOrElse(str,0) + 1))
  //添加一对映射
}
println(m.mkString(","))

//abstraction -> 1,At -> 1,GraphX -> 4,for -> 1................
  1. 重复前一个练习,这次用已排序的映射,以便单词可以按顺序打印出来。
    
    import java.io.File
    import java.util.Scanner

val in = new Scanner(new File("/text.txt")) val map = scala.collection.immutable.SortedMap[String, Int]() var m = map //不可变(val)映射 while(in.hasNext()){ val str = in.next() m += (str -> (m.getOrElse(str,0) + 1)) //添加一对映射 } println(m.mkString(","))

//(alpha) -> 1,(e.g., -> 3,API -> 1,API. -> 1............................


8. 编写一个函数minmax(values: Array[Int]),返回数组中最小值和最大值的对偶。
```scala
val t =Array(1,2,3,4,5)
val min = t.min
val max = t.max
printf("%d, %d\n",min,max)

//1, 5
  1. 编写一个函数lteqgt(values: Array[Int], v: Int),返回数组中小于v,等于v和大于v的数量,要求三个值一起返回。
    
    def iteqgt(values: Array[Int], v: Int) = {
    var l,e,r = 0;
    for (i <- values){
    if (i<v)
      l += 1
    else if(i == v)
      e += 1
    else
      r += 1
    }
    (l,e,r)
    }
    val a = Array(1,2,3,4,5,6)
    val ans = iteqgt(a,3)
    println(ans)

//(2,1,3)


10. 当你将两个字符串拉链在一起,比如”Hello”.zip(“World”),会是什么结果?想出一个讲得通的用例。
```scala
val t1 = "hello".zip("world")
val t2 = "ab".zip("cde")
val t3 = "abc".zip("d")

println(t1)
println(t2)
println(t3)

//Vector((h,w), (e,o), (l,r), (l,l), (o,d))
//Vector((a,c), (b,d))
//Vector((a,d))
justtreee commented 6 years ago

第五章 类

其实与Java或C++的写法差不多,但更简洁。最基本的写法:

class Counter {
  private var value = 0 //必须初始化
  def increment() = { value += 1}
  def current() = value
}

val myCnt = new Counter //或Counter()
myCnt.increment()
println(myCnt.current()) 

//1

对于私有属性,使用getter和setter方法进行获取和设置。这与Java或C++一致。在Scala中

每个类都有一个主要的构造器,这个构造器和类定义交织在一起,它的参数直接成为类的字段。主构造器执行类体中所有的语句。

辅助构造器是可选的,叫做this

本章直接靠练习学习吧。

练习

  1. 改进5.1节的Counter类,让它不要在Int.MaxValue时变成负数。
    
    class Counter {
    private var value = 0 //必须初始化
    def increment() = {
    if((value+1).isValidInt)
      value += 1
    }
    def current() = value
    }

val myCnt = new Counter //或Counter() for(_ <- 1 to Int.MaxValue) myCnt.increment() println(myCnt.current())

//2147483647


2. 编写一个BankAccount类,加入deposit和withdraw方法,和一个只读的balance属性。
```scala
class BankAccount(val banlance : Int){
  def deposit = {
    println("depodit")
  }
  def withdraw = {
    println("withdraw")
  }
}
val a = new BankAccount(200)
a.deposit
a.withdraw
println(a.banlance)

//depodit
//withdraw
//200
  1. 编写一个Time类,加入只读属性hours和minutes,和一个检查某一时刻是否早于另一时刻的方法before(other: Time): boolean。Time对象应该以new Time(hrs, min)方式构建,其中hrs小时数以军用时间格式呈现(介于0和23之间)。
    
    class Time(val vh:Int, val vm:Int)
    {
    private val hrs = vh
    private val min = vm
    def hours = hrs
    def minutes = min
    def before(other: Time) : Boolean = {
    other.hours > this.hours || (other.hours == this.hours && other.minutes > this.minutes)
    }
    }

val t = new Time(23,10) println(t.before(new Time(23,11)))

//true


4. 重新实现前一个练习中的Time类,将内部呈现改成自午夜起的分钟数(介于0到24x60-1之间)。不要改变公有接口。也就是说,客户端代码不应因你的修改而受影响。
```scala
class Time(val vh:Int, val vm:Int)
{
  private val hrs = vh
  private val min = vm
  def hours = hrs
  def minutes = min
  def before(other: Time) : Boolean = {
    other.hours > this.hours || (other.hours == this.hours && other.minutes > this.minutes)
  }
  def total = (this.hours * 60 + this.minutes)
}

val t =  new Time(23,10)
println(t.before(new Time(23,11)))
  1. 在5.2节的Person类中提供一个主构造器,将负年龄转换为0。
    
    class Person
    {
    private var page = 0
    def age_= (v :Int) {//age_= 的=前面不能有空格
    if (v < 0)
      page = 0
    else
      page = v
    }
    def age = page
    }
    val p = new Person()
    p.age = -1
    println(p.age)

//0


7. 编写一个Person类,其主构造器接受一个字符串,该字符串包含名字、空格和姓,如new Person(“Fred Smith”)。提供只读属性firstName和LastName。
```scala
class Person(val name : String)
{
  val firstName = name.split(" ")(0)
  val lastName = name.split(" ")(1)
}
val p = new Person("Fred Smith")
println(p.firstName)
println(p.lastName)

//Fred
//Smith
  1. 创建一个Car类,以只读属性对应制造商、型号名称、型号年份以及一个可读写的属性用于车牌。提供四组构造器。每一个构造器都要求制造商和型号名称为必填。型号年份以及车牌为可选,如果未填,则型号年份设置为-1,车牌设置为空字符串。你会选择哪一个作为你的主构造器?为什么?

    
    class Car(val maker : String, val name : String)
    {
    private var privateModel = -1
    var licence = ""
    
    def this(maker : String, name : String, model : Int) {
    this(maker, name)
    this.privateModel = model
    }
    
    def this(maker : String, name : String, licence : String) {
    this(maker, name)
    this.licence = licence
    }
    
    def this(maker : String, name : String, model : Int, licence : String) {
    this(maker, name, model)
    this.licence = licence
    }
    
    def model = privateModel
    }

val car = new Car("Tom Smith", "tst", 2017, "GG6666") println(car.model)

justtreee commented 6 years ago

第六章 对象

在本章中,会学到何时使用Scala的object语法结构,在需要某个类的单个实例,或者向想为其他值或函数找一个可以挂靠的地方是,就会用到它。

每个Scala程序都必须从一个对象的main方法开始,这个方法的类型为Array[String]=>Unit:

object Hello{
  def main(args : Array[String]): Unit = {
    println("hello")
  }
}

本章主要也是以练习学习为主。

  1. 编写一个Conversions对象,加入inchesToCentimeters、gallonsToLiters和milesToKilometers方法。
    
    object Conversions{
    def inchesToCentimeters(v: Double) = {
    v * 2.54
    }
    def gallonsToliters(v: Double) = {
    v * 3.785
    }
    def milesToKilometers(v: Double) = {
    v * 1.609
    }
    }
    println(Conversions.inchesToCentimeters(3.3))

//8.382


2. 前一个练习不是很面向对象,提供一个通用的超类UnitConversion并定义扩展该超类的InchesToCentimeters、GallonsToLiters和MilesToKilometers对象。
```scala
abstract class UnitConversion{
  def convert(v : Double) : Double
}
object inchToCentimeters extends UnitConversion{
  override def convert(v: Double): Double = v*2.54
}
object gallonToLiters extends UnitConversion{
  override def convert(v: Double): Double = v*3.7854
}
object milesToKilometers extends UnitConversion{
  override def convert(v: Double): Double = v*1.6093
}
println(inchToCentimeters.convert(3))
println(gallonToLiters.convert(3.3))
println(milesToKilometers.convert(3.3))

//7.62
//12.491819999999999
//5.310689999999999
  1. 定义一个Point类和一个伴生对象,使得我们可以不用new而直接用Point(3,4)来构造Point实例。
    
    class Point(val x : Double, val y : Double){
    }
    object Point{
    def apply(x:Double,y:Double) = new Point(x, y)
    }
    val p = Point(3.3,4.4)
    println(p.x)

//3.3


5. 编写一个Scala应用程序,使用App特质,以反序打印命令行参数,用空格隔开。
```scala
object TestApp extends App
{
  println(args.reverse.mkString(","))
}
  1. 编写一个扑克牌4种花色的枚举,让其toString方法分别返回♣、♦、♥和♠。
    
    object Enum extends Enumeration{
    val Club = Value(0, "♣")
    val Diomand = Value(1, "♦")
    val Heart = Value(2, "♥")
    val Spade = Value(3, "♠")
    }
    object Test extends App{
    for (c <- Enum.values)
    println(c.toString)
    }

//♣ //♦ //♥ //♠


7. 编写一个函数,检查某张牌的花色是否为红色。

```scala
object Enum extends Enumeration{
  val Club = Value(0, "♣")
  val Diomand = Value(1, "♦")
  val Heart = Value(2, "♥")
  val Spade = Value(3, "♠")
}
object Test extends App{
  for (c <- Enum.values){
    println(c.toString)
    println(check(c))
  }

  def check(value: Enum.Value) = {
    if(value == Enum.Heart || value == Enum.Diomand)
      true
    else
      false
  }
}

//♣
//false
//♦
//true
//♥
//true
//♠
//false
  1. 编写一个枚举,描述RGB立方体的8个角。ID使用颜色值(例如,红色是0xff0000)。
object RGBCube extends Enumeration {
  val R = Value(0xff0000)
  val G = Value(0x00ff00)
  val B = Value(0x0000ff)
  val RG = Value(0xffff00)
  val RB = Value(0xff00ff)
  val GB = Value(0x00ffff)
  val RGB = Value(0xffffff)
  val BLACK = Value(0x000000)
}
object Test extends App{
  for (c <- RGBCube.values) {
    printf("#%06x\n", c.id)
  }
}

//#0000ff
//#00ff00
//#00ffff
//#ff0000
//#ff00ff
//#ffff00
//#ffffff