scala映射和元组浅谈及代码示例分享
映射是键/值的对偶集合。Scala有一个通用的叫法–元组–n个对象的聚集,这些对象并不一定是相同类型的。对偶不过是一个n=2的元组。元组在那种需要将两个或更多值聚集在一起的场合特别有用。
一、构造映射:
a.不可变映射:
//两种方式都可以
val scores = Map("Alice" -> 10, "Bob" -> 3,"Cindy" -> 8)
val scores = Map(("Alice",10), ("Bob", 3),("Cindy",8))
b.可变映射:
val scores = scala.collection.mutable.Map("Alice" -> 10, "Bob" -> 3,"Cindy" -> 8)
c.可变空映射:
val scores = scala.collection.mutable.Map[String,Int]()
映射是一种将键映射到值的函数。只不过两者的区别在于,通常函数用于计算值,而映射仅用于查询值。
二、获取映射中的值:
在scala中,函数和映射之间的相似性尤为明显,因为你将使用()表示法来查询某个键对应的值。
val scores = Map("Alice" -> 10, "Bob" -> 3,"Cindy" -> 8)
val bobsScore = scores("Bob")
如果映射中不包含请求中使用的键则会抛出空指针异常。想要检查映射中是否有某个指定的键可以使用contains方法:
val scores = Map("Alice" -> 10, "Bob" -> 3,"Cindy" -> 8)
// 写法1
val bobsScore = if (scores.contains("Bob")) scores("Bob") else "not matches..."
// 写法2
val bobsScore = scores.getOrElse("Bob","not matches...")
映射.get(key)这样的调用返回一个Option对象,要么是Some(键对应的值),要么是None。
val scores = Map("Alice" -> 10, "Bob" -> 3,"Cindy" -> 8)
val zel = scores.get("Bob") //返回Some(3)
val zel = scores.get("zelda") // 返回None,因为不存在zelda这个键
三、更新映射中的值:
在可变映射中,可以更新某个映射的值,或添加一个新的映射关系,做法是在=的左边使用()。
val scores = scala.collection.mutable.Map("Alice" -> 10, "Bob" -> 3,"Cindy" -> 8, "Lee" -> null)
scores("Lee") = 9
scores("Ann") = 8
// 输出为 HashMap(Ann -> 8, Bob -> 3, Cindy -> 8, Lee -> 9, Alice -> 10)
也可以使用+=来添加其他或修改映射关系,或使用-=来删除已有的键。
scores += ("Alice" -> 12,"Tony" -> 15) //修改Alice分数为12,添加Tony分数为15
scores -= ("Alice") //删除Alice的映射关系
虽然不能更新不可变映射,但是可以获取一个包含修改的新映射:
val scores = Map("Alice" -> 10, "Bob" -> 3,"Cindy" -> 8, "Lee" -> null)
val scores1 = scores + ("Alice" -> 12,"Tony" -> 15)
// 输出为HashMap(Bob -> 3, Tony -> 15, Alice -> 12, Lee -> null, Cindy -> 8)
或者在创建时直接创建var变量:
var scores = Map("Alice" -> 10, "Bob" -> 3,"Cindy" -> 8, "Lee" -> null)
scores += ("Alice" -> 12,"Tony" -> 15)
// 输出为HashMap(Bob -> 3, Tony -> 15, Alice -> 12, Lee -> null, Cindy -> 8)
四、迭代映射:
下面是一个简单的迭代映射的例子:
for((k,v) <- 映射) 处理 k 和 v
在这个例子中,使用了for循环中的模式匹配。这样一来,不需要冗杂的方法调用,就可以得到每一个对偶的键和值。
如果出于某些原因,只需要访问键或值,则可以使用keySet和values方法。values方法返回一个Iterable,这个iterable可以在for循环中使用。
var scores = Map("Alice" -> 10, "Bob" -> 3,"Cindy" -> 8, "Lee" -> null)
scores += ("Alice" -> 12,"Tony" -> 15)
println(scores.keySet)
//输出为Set(Bob, Tony, Alice, Lee, Cindy)
println(scores.values)
//输出为Iterable(3, 15, 12, null, 8)
此外要执行映射反转时还可使用以下语句:
val result1 =for ((k,v)<- scores) yield (v,k)
五、已排序映射:
映射有两种常见的实现策略:哈希表和平衡树。哈希表使用键的哈希码来划定位置,因此遍历会以一种不可预期的顺序交出元素。默认情况下,Scala给你的是基于哈希表的映射,因为它比较高效。如果需要按照顺序依次访问映射中的键,可以使用SortedMap。
val scores = scala.collection.mutable.SortedMap("Alice" -> 10, "Bob" -> 3,"Cindy" -> 8, "Lee" -> null)
scores += ("Alice" -> 12,"Tony" -> 15)
println(scores)
//输出为TreeMap(Alice -> 12, Bob -> 3, Cindy -> 8, Lee -> null, Tony -> 15),可以看到是按顺序输出的,按插入顺序输出则可以使用,LinkedHashMap
六、与Java的互操作:
如果通过Java方法调用得到了一个Java映射,你可能想要把它转换为一个Scala映射,以便使用更加便捷的Scala映射API。这对于需要操作Scala并未提供的可变树形映射的情况很有用。
只需要引入如下语句:
import scala.collection.JavaConverters.mapAsScalaMap
然后通过指定的Scala映射类型来触发转换:
val scores:scala.collection.mutable.Map[String,Int]= new java.util.TreeMap[String,Int]
此外,你还可以得到从java.util.Properties到Map[String,String]的转换:
import scala.collection.JavaConversions.propertiesAsScalaMap
val props : scala.collection.Map[String,String] = System.getProperties()
相反,要把Scala映射传递给预期Java映射的方法,提供相反的隐式转换即可。
import scala.collection.JavaConversions.mapAsJavaMap
import java.awt.font.TextAttribute //引入下面的映射会用到的键
val attrs = Map(FAMILY->"Serif",SIZE->12) //Scala映射
val font = new java.awt.Font(attrs) //该方法预期产生一个Java映射
七、元组:
映射是键值对偶的集合。对偶是元组最简单的形态–元组是不同类型的值的聚集。
元组的值是通过将单个的值包含在圆括号中构建的。例如:
val a = (1, 3.14, "Fred")
可以使用方法_1、_2、_3访问元组的组元。
val second = a._2
和数组或字符串中的位置不同,元组的各组元是从1开始的,而不是从0开始的。
通常使用模式匹配来获取元组的组成部件,例如:
val (first,second,third) = a // first为1,second为3.14,third为"Fred"
如果并不是所有部件都需要,可以在不需要的部件位置上使用_:
val (first,second,_) = a
元组可以用于函数需要返回不止一个值的情况。例如,StringOps的partition方法返回的是一对字符串,分别包含了满足某个条件和不满足某个条件的字符:
"New York".partition(_.isUpper) //返回("Ny","ew ork")
八、拉链操作:
使用元组的原因之一是把多个值绑在一起,以便它们能够被一起处理,这通常可以使用zip方法来完成。
val symbols = Array("<","-",">")
val counts = Array(2,10,2)
val pairs = symbols.zip(counts)
for((s,n) <- pairs) print(s * n)
// 输出为<<---------->>,即2个<、10个-、2个>