Scala集合:Map

Map是一个key-value 对的集合。在其它语言中,它被称为词典、关联数组、或HashMap。这是一个根据key查找value的高效的数据结构。

下面的代码段演示了怎样创建和使用一个Map:

val capitals = Map("美国" -> "华盛顿", "英国" -> "伦敦","中国" -> "北京")
val chinaCapital = capitals("中国")
println(chinaCapital)

下面这个示例是对Map进行迭代。

val booksMap = Map(101 -> "Scala", 102 -> "Spark")

val iterator = booksMap.keySet.iterator
while (iterator.hasNext) {
   var key = iterator.next
   // println(s"图书Id:$key,图书名称:${booksMap.get(key)}")
   println(s"图书Id:$key,图书名称:${booksMap(key)}")
}

输出如下所示:

图书Id:101,图书名称:Scala
图书Id:102,图书名称:Spark

【示例】创建使用不可变Map的示例。

object MapDemo {
  def main(args: Array[String]): Unit = {
    println("1: 初始化一个带有3个元素的Map - 使用key/value元组")
    // val map1: Map[String, String] = Map(("PG","苹果"),("XG","西瓜"),("PTG","葡萄干"))
    val map1 = Map(("PG","苹果"),("XG","西瓜"),("PTG","葡萄干")) // 类型推断
    println(s"map1的元素 = $map1")

    println("\n2: 使用key->value表示法初始化Map")
    // val map2: Map[String, String] = Map("PG" -> "苹果", "XG" -> "西瓜", "PTG" -> "葡萄干")
    val map2 = Map("PG" -> "苹果", "XG" -> "西瓜", "PTG" -> "葡萄干")
    println(s"map2的元素 = $map2")

    println("\n3: 通过特定键访问元素")
    println(s"Key是PG的元素 = ${map2("PG")}")
    println(s"Key是XG的元素 = ${map2("XG")}")
    println(s"Key是PTG的元素 = ${map2("PTG")}")
    println(s"Key是HLG的元素 = ${map2.get("HLG")}")     // 访问不存在的key
    println(s"Key是HLG的元素 = ${map2.getOrElse("HLG","火龙果")}")

    println("\n4: 使用 + 添加元素")
    // val map3: Map[String, String] = map1 + ("HLG" -> "火龙果")
    val map3: Map[String, String] = map1 + ("PTG" -> "火龙果") // 也可用来修改元素值
    println(s"map3 = $map3")

    println("\n5: 使用 ++ 将两个Map 添加到一起")
    val map4: Map[String, String] = map3 ++ map2
    println(s"map4 = $map4")

    println("\n6: 使用 - 从Map 删除key及其value")
    val map5: Map[String, String] = map4 - "PG"
    println(s"Map移除了PG key及其value = $map5")

    println("\n7: 初始化一个空的Map")
    val emptyMap: Map[String,String] = Map.empty[String,String]
    println(s"Empty Map = $emptyMap")
  }
}

【示例】如何遍历一个Map集合。

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

    // map的遍历
    val map = Map(("aa",1),("bb",2),("cc",5),("dd",3))

    map.foreach { t =>
      val (x, y) = t
      println(s"key=$x, value=$y")
    }

    map.foreach { t =>
      println(s"k=${t._1}, v=${t._2}")
    }

    for(item <- map){
      val (x, y) = item
      println(s"key=$x,value=$y")
    }

    for((k,v) <- map){
      println(s"k = $k, v = $v")
    }

    for(key <- map.keySet){
      println(s"key=$key,value=${map(key)}")
    }

    for(item <- map){
      println(item)
    }

    for(item <- map){
      println(s"key=${item._1}, value=${item._2}")
    }

    for(v <- map.values){
      println(s"value=$v")
    }
  }
}

下面的代码示例演示的Map的创建和操作:

// 创建
var m1 = Map(("zhang3" -> 20), ("li4" -> 23), ("wang5" -> 21))
var m2 = Map(("zhang3", 20), ("li4", 23), ("wang5", 21))   // 也可使用元组创建

var m = scala.collection.mutable.Map(("zhang3", 20), ("li4", 23), ("wang5", 21))
// var m3 = scala.collection.mutable.Map[String, Int]()    // 定义空 map,要用可变的才有意义。

// 添加和更新:+=  ++=
m += (("zhao6", 22))
m ++= Map(("a" -> 1), ("b" -> 2))
m

// updated,没有增加,有了替换
m = m.updated("zheng7", 19)  // 和上面方法一样
m

m.put("wu", 22)
m

// 删除
m -= ("zhang3")     // 删除一个元素:按指定的key删除

m.clear()   		// 清空
m

/* -- 查询 -- */
println("---------查询-------------")
var m4 = Map(("zhang3", 20), ("li4", 23), ("wang5", 21))
m4("zhang3")
// m4("aaa")     	// 会出错,不友好
m4.get("aaa")    	// 友好方式,推荐
m4.getOrElse("aaa",23)
m4.getOrElse("zhang3",23)

/* -- 遍历 -- */
var m5 = Map(("zhang3", 20), ("li4", 23), ("wang5", 21))

// 方法 1:直接打印 entry
for (entry <- m5) {
   println(entry) 
}

println("-------------")
// 方法 2:直接打印 key,顺手输出 value
for (key <- m5.keySet) {
    println(key + ":" + m5(key))
}

println("-------------")
for((k,v) <- m5){
    println(k + "," + v)
}

println("-------------")
// 方法 3.foreach
m5.foreach(e => {
   val (k, v) = e
   println(k + "," + v)
})

println("-------------")
// 方法 4
m5.foreach(e => println(e._1 + "," + e._2))

【示例】不可变的HashMap示例。

import scala.collection.immutable.HashMap

object HashMapDemo {
  def main(args: Array[String]): Unit = {
    println("1: 初始化一个带有3个元素的HashMap - 使用key/value元组")
    // val hashMap1: HashMap[String, String] = HashMap(("PG","苹果"),("XG","西瓜"),("PTG","葡萄干"))
    val hashMap1 = HashMap(("PG","苹果"),("XG","西瓜"),("PTG","葡萄干")) // 类型推断
    println(s"hashMap1的元素 = $hashMap1")

    println("\n2: 使用key->value表示法初始化Map")
    // val hashMap2: HashMap[String, String] = HashMap("PG" -> "苹果", "XG" -> "西瓜", "PTG" -> "葡萄干")
    val hashMap2 = HashMap("PG" -> "苹果", "XG" -> "西瓜", "PTG" -> "葡萄干")
    println(s"hashMap2的元素 = $hashMap2")

    println("\n3: 通过特定键访问元素")
    println(s"Key是PG的元素 = ${hashMap2("PG")}")
    println(s"Key是XG的元素 = ${hashMap2("XG")}")
    println(s"Key是PTG的元素 = ${hashMap2("PTG")}")
    println(s"Key是HLG的元素 = ${hashMap2.get("HLG")}")     // 访问不存在的key
    println(s"Key是HLG的元素 = ${hashMap2.getOrElse("HLG","火龙果")}")

    println("\n4: 使用 + 添加元素")
    // val hashMap3: HashMap[String, String] = hashMap1 + ("HLG" -> "火龙果")
    val hashMap3: HashMap[String, String] = hashMap1 + ("PTG" -> "火龙果") // 也可用来修改元素值
    println(s"hashMap3 = $hashMap3")

    println("\n5: 使用 ++ 将两个Map 添加到一起")
    val hashMap4: Map[String, String] = hashMap3 ++ hashMap2
    println(s"map4 = $hashMap4")

    println("\n6: 使用 - 从Map 删除key及其value")
    val hashMap5: Map[String, String] = hashMap4 - "PG"
    println(s"HashMap移除了PG key及其value = $hashMap5")

    println("\n7: 初始化一个空的Map")
    val emptyMap: HashMap[String,String] = HashMap.empty[String,String]
    println(s"Empty HashMap = $emptyMap")
  }
}

【示例】不可变的TreeMap示例。

import scala.collection.immutable.TreeMap

object TreeMapDemo {
  def main(args: Array[String]): Unit = {
      println("1: 初始化一个带有3个元素的HashMap - 使用key/value元组")
      // val treeMap1: TreeMap[String, String] = TreeMap(("PG","苹果"),("XG","西瓜"),("PTG","葡萄干"))
      val treeMap1 = TreeMap(("PG","苹果"),("XG","西瓜"),("PTG","葡萄干")) // 类型推断
      println(s"hashMap1的元素 = $treeMap1")

      println("\n2: 使用key->value表示法初始化Map")
      // val treeMap2: TreeMap[String, String] = TreeMap("PG" -> "苹果", "XG" -> "西瓜", "PTG" -> "葡萄干")
      val treeMap2 = TreeMap("PG" -> "苹果", "XG" -> "西瓜", "PTG" -> "葡萄干")
      println(s"hashMap2的元素 = $treeMap2")

      println("\n3: 通过特定键访问元素")
      println(s"Key是PG的元素 = ${treeMap2("PG")}")
      println(s"Key是XG的元素 = ${treeMap2("XG")}")
      println(s"Key是PTG的元素 = ${treeMap2("PTG")}")
      println(s"Key是HLG的元素 = ${treeMap2.get("HLG")}")     // 访问不存在的key
      println(s"Key是HLG的元素 = ${treeMap2.getOrElse("HLG","火龙果")}")

      println("\n4: 使用 + 添加元素")
      // val treeMap3: TreeMap[String, String] = hashMap1 + ("HLG" -> "火龙果")
      val treeMap3: TreeMap[String, String] = treeMap1 + ("PTG" -> "火龙果") // 也可用来修改元素值
      println(s"treeMap3 = $treeMap3")

      println("\n5: 使用 ++ 将两个TreeMap 添加到一起")
      val treeMap4: TreeMap[String, String] = treeMap3 ++ treeMap2
      println(s"treeMap4 = $treeMap4")

      println("\n6: 使用 - 从TreeMap 删除key及其value")
      val treeMap5: TreeMap[String, String] = treeMap4 - "PG"
      println(s"TreeMap移除了PG key及其value = $treeMap5")

      println("\n7: 将TreeMap的顺序改为降序")
      object AlphabetOrdering extends Ordering[String] {
          def compare(key1:String, key2:String): Int = key2.compareTo(key1)
      }
      val treeMap6: TreeMap[String, String] = TreeMap(
          ("PG","苹果"),
          ("XG","西瓜"),
          ("PTG","葡萄干")
      )(AlphabetOrdering)
      println(s"treeMap6的元素按降序排列 = $treeMap6")

      println("\n8: 初始化一个空的TreeMap")
      val mptyTreeMap: TreeMap[String,String] = TreeMap.empty[String,String]
      println(s"Empty TreeMap = $mptyTreeMap")
  }
}

【示例】不可变的ListMap示例。

import scala.collection.immutable.ListMap

object ListMapDemo {
  def main(args: Array[String]): Unit = {
    println("1: 初始化一个ListMap")
    val listMap1: ListMap[String, String] = ListMap(
      "PG" -> "苹果",
      "XG" -> "西瓜",
      "PTG" -> "葡萄干"
    )
    println(s"listMap1的元素 = $listMap1")

    println("\n2: 通过ListMap中的特定键访问元素")
    println(s"key PG对应的元素 = ${listMap1("PG")}")
    println(s"key XG对应的元素 = ${listMap1("XG")}")
    println(s"key PTG对应的元素 = ${listMap1("PTG")}")

    println("\n3: ListMap是一个递归数据结构")
    println(s"head of ListMap = ${listMap1.head}")  // 返回一个元组
    println(s"tail of ListMap = ${listMap1.tail}")

    println("\n4: 使用 + 向ListMap添加元素")
    // val listMap2: ListMap[String, String] = listMap1 + ("KD" -> "Krispy Kreme Donut")
    val listMap2 = listMap1 + ("HLG" -> "火龙果")
    println(s"listMap2的元素 = $listMap2")

    println("\n5: 使用 ++ 添加两个ListMap到一起")
    val listMap3: ListMap[String, String] = listMap1 ++ listMap2
    println(s"listMap3的元素 = $listMap3")

    println("\n6: 使用 - 从ListMap中删除key和value")
    val listMap4: ListMap[String, String] = listMap1 - "PG"
    println(s"没有PG及其值的ListMap = $listMap4")

    println("\n7: 初始化一个空的ListMap")
    val emptyListMap: ListMap[String, String] = ListMap.empty[String,String]
    println(s"key和value都是String类型的空ListMap = $emptyListMap")
  }
}

《PySpark原理深入与编程实战》