• [转] Scala 的集合类型与数组操作


    [From] https://blog.csdn.net/gongxifacai_believe/article/details/81916659

    版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/gongxifacai_believe/article/details/81916659

    1、Scala中的集合

    Scala有一个非常通用丰富强大可组合的集合库;集合是高阶的,并拥有一大套操作方法。Scala的所有的集合类都可以在包 scala.collection 包中找到,其中集合类都是高级抽象类或特性。

    Iterable[T] 是所有可遍历的集合,它提供了迭代的方法(foreach)。
    Seq[T] 是有序集合。
    Set[T]是数学上的集合(无序且不重复)。
    Map[T]是关联数组,也是无序的。
    Scala 集合类系统地区分了可变的和不可变的集合。
    可变集合可以在适当的地方被更新或扩展,意味着你可以修改、添加、移除一个集合的元素。而不可变集合类,相比之下永远不会改变。不过,你仍然可以模拟添加移除或更新操作。但是这些操作将在每一种情况下都返回一个新的集合,同时使原来的集合不发生改变。可变的集合类位于 scala.collection.mutable 包中,而不可变的集合位于 scala.collection.immutable.scala.collection 包中。集合既可以是可变的,也可以是不可变的。
    官方文档:http://www.scala-lang.org/docu/files/collections-api/collections.html
    所有集合组件图示如下:

     

    2、Scala集合List和Set

    Scala集合中的seq包含了:Range和ArrayBuffer以及List。这些组件区分了可变和不可变类型。
    (1)创建list集合

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

    (2)Scala中的list包含两个部分,head+tail或head+Nil
    list.head 代表返回第一个元素,list.tail 代表返回一个不包含第一个元素的集合,Nil代表空的list集合。

    val list2 = 1::Nil

    注意集合的顺序,前面是元素后面是集合

    val list3 = 2::list2

    前面的元素就是新的list的head,后面的就是新的list的tail
    (3)创建一个可变的list集合

    val listBuffer = scala.collection.mutable.ListBufferInt

    (4)添加元素

    listBuffer += 2
    listBuffer +=(3,4,5)
    listBuffer ++= List(6,7,8)
    listBuffer -= (4,7)

    (5)list练习:指定前缀
    需求:使用递归函数给list中的每个元素都加上指定的前缀,并且打印出加上前缀的元素。
    注意:最后一个元素的时候它的tail就是Nil。

     def dtor(list: List[Int], pfix: String){
        if(list != Nil){
            println(pfix + list.head)
            dtor(list.tail,pfix)
        }
     }

    (6)set集合创建
    不可变集合:

     val set = Set(1,2,3,4)

    可变集合:

    val s = scala.collection.mutable.Set(1,2)

    添加元素:
    不可变集合:+ ++ - –
    可变集合:+= ++= -= --=

     

    3、Scala集合Map与Tuple

    (1)创建Map
    创建一个不可变的Map:

    val ages = Map(“Leo” -> 30, “Jen” -> 25, “Jack” -> 23)
    ages(“Leo”) = 31

    创建一个可变的Map:

    val ages = scala.collection.mutable.Map(“Leo” -> 30, “Jen” -> 25, “Jack” -> 23)
    ages(“Leo”) = 31

    使用另外一种方式定义Map元素:

    val ages = Map((“Leo”, 30), (“Jen”, 25), (“Jack”, 23))

    创建一个空的HashMap:

    val ages = new scala.collection.mutable.HashMap[String, Int]

    (2)访问Map的元素
    获取指定key对应的value,如果key不存在,会报错:

    val leoAge = ages(“Leo”)
    val leoAge = ages(“leo”)

    使用contains函数检查key是否存在:

    val leoAge = if (ages.contains(“leo”)) ages(“leo”) else 0

    getOrElse函数:

    val leoAge = ages.getOrElse(“leo”, 0)

    (3)修改Map的元素
    更新Map的元素:

    ages(“Leo”) = 31

    增加多个元素:

    ages += (“Mike” -> 35, “Tom” -> 40)

    移除元素:

    ages -= “Mike”

    更新不可变的map:

    val ages2 = ages + (“Mike” -> 36, “Tom” -> 40)

    移除不可变map的元素:

    val ages3 = ages - “Tom”

    (4)遍历Map
    遍历map的entrySet:

    for ((key, value) <- ages) println(key + ” ” + value)

    遍历map的key:

    for (key <- ages.keySet) println(key)

    遍历map的value:

    for (value <- ages.values) println(value)

    生成新map,反转key和value:

    for ((key, value) <- ages) yield (value, key)

    (5)SortedMap和LinkedHashMap
    SortedMap可以自动对Map的key的排序:

    val ages = scala.collection.immutable.SortedMap(“leo” -> 30, “alice” -> 15, “jen” -> 25)

    LinkedHashMap可以记住插入entry的顺序:

    val ages = new scala.collection.mutable.LinkedHashMap[String, Int]
    ages(“leo”) = 30
    ages(“alice”) = 15
    ages(“jen”) = 25

    (6)Map的元素类型—Tuple
    Map的每一个元素(key,value)就称作:tuple元组对
    简单的Tuple定义:

    val t = (“leo”, 30)

    访问Tuple:

    t._1

    zip拉链操作:

    val names = Array(“leo”, “jack”, “mike”)
    val ages = Array(30, 24, 26)
    val nameAges = names.zip(ages)
    for ((name, age) <- nameAges) println(name + “: ” + age)

     

    4、数组Array

    在Scala中,Array代表的含义与Java中类似,也是长度不可改变的数组。此外,由于Scala与Java都是运行在JVM中,双方可以互相调用,因此Scala数组的底层实际上是Java数组。例如字符串数组在底层就是Java的String[],整数数组在底层就是Java的Int[]。
    (1)数组初始化后,长度就固定下来了,而且元素全部根据其类型初始化

    val a = new ArrayInt
    a(0)
    a(0) = 1
    val a = new ArrayString

    (2)可以直接使用Array()创建数组,元素类型自动推断

    val a = Array(“hello”, “world”)
    a(0) = “hi”
    val a = Array(“leo”, 30)

    (3)数组元素求和

    val a = Array(1, 2, 3, 4, 5)
    val sum = a.sum

    (4)获取数组最大值

    val max = a.max

    (5)对数组进行排序

    scala.util.Sorting.quickSort(a)

    (6)获取数组中所有元素内容

    a.mkString
    a.mkString(“, “)
    a.mkString(“<”, “,”, “>”)

    (7)toString函数

    a.toString

     

    5、数组ArrayBuffer

    在Scala中,如果需要类似于Java中的ArrayList这种长度可变的集合类,则可以使用ArrayBuffer。
    (1)如果不想每次都使用全限定名,则可以预先导入ArrayBuffer类

    import scala.collection.mutable.ArrayBuffer

    (2)使用ArrayBuffer()的方式可以创建一个空的ArrayBuffer

    val b = ArrayBufferInt

    (3)使用+=操作符,可以添加一个元素,或者多个元素。这个语法必须要谨记在心!因为spark源码里大量使用了这种集合操作语法!

    b += 1
    b += (2, 3, 4, 5)

    (4)使用++=操作符,可以添加其他集合中的所有元素

    b ++= Array(6, 7, 8, 9, 10)

    (5)使用trimEnd()函数,可以从尾部截断指定个数的元素

    b.trimEnd(5)

    (6)使用insert()函数可以在指定位置插入元素,但是这种操作效率很低,因为需要移动指定位置后的所有元素。

    b.insert(5, 6)
    b.insert(6, 7, 8, 9, 10)

    (7)使用remove()函数可以移除指定位置的元素

    b.remove(1)
    b.remove(1, 3)

    (8)Array与ArrayBuffer可以互相进行转换

    b.toArray
    a.toBuffer

    (9)使用for循环和until遍历Array / ArrayBuffer
    until是RichInt提供的函数

    for (i <- 0 until b.length)
    println(b(i))

    (10)跳跃遍历Array / ArrayBuffer

    for(i <- 0 until (b.length, 2))
    println(b(i))

    (11)从尾部遍历Array / ArrayBuffer

    for(i <- (0 until b.length).reverse)
    println(b(i))

    (12)使用“增强for循环”遍历Array / ArrayBuffer

    for (e <- b)
    println(e)

    (13)toString函数

    b.toString

     

    6、数组操作

    (1)使用yield和函数式编程转换数组
    对Array进行转换,获取的还是Array

    val a = Array(1, 2, 3, 4, 5)
    val a2 = for (ele <- a) yield ele * ele

    对ArrayBuffer进行转换,获取的还是ArrayBuffer

    val b = ArrayBufferInt
    b += (1, 2, 3, 4, 5)
    val b2 = for (ele <- b) yield ele * ele

    结合if守卫,仅转换需要的元素

    val a3 = for (ele <- if ele % 2 == 0) yield ele * ele

    (2)使用函数式编程转换数组(通常使用第一种方式)

    a.filter(_ % 2 == 0).map(2 * _)
    a.filter { _ % 2 == 0 } map { 2 * _ }

    (3)算法案例:移除第一个负数之后的所有负数

    1.   算法一:
      构建数组:
    val a = ArrayBufferInt
    a += (1, 2, 3, 4, 5, -1, -3, -5, -9)

    每发现一个第一个负数之后的负数,就进行移除,性能较差,多次移动数组:

    var foundFirstNegative = false
    var arrayLength = a.length
    var index = 0
    while (index < arrayLength) {
    	if (a(index) >= 0) {
    		index += 1
    	} else {
    	if (!foundFirstNegative) { foundFirstNegative = true; index += 1 }
    	else { a.remove(index); arrayLength -= 1 }
    	}
    }

    2.  算法二:
    重新构建数组:

    val a = ArrayBufferInt
    a += (1, 2, 3, 4, 5, -1, -3, -5, -9)

    每记录所有不需要移除的元素的索引,稍后一次性移除所有需要移除的元素。该算法性能较高,数组内的元素迁移只要执行一次即可。

    var foundFirstNegative = false
    val keepIndexes = for (i <- 0 until a.length if !foundFirstNegative || a(i) >= 0) yield {
    	if (a(i) < 0) foundFirstNegative = true
    	i
    }
    for (i <- 0 until keepIndexes.length) { a(i) = a(keepIndexes(i)) }
    a.trimEnd(a.length - keepIndexes.length) 
    

     

  • 相关阅读:
    Shell脚本 --- 正则表达式和文本处理工具
    python的eval、exec函数
    内置函数 Built-in Functions
    关于Python中的lambda
    Python中*args和**kwargs的区别
    Python基础-10-文件操作
    Python基础-09-内置函数
    Python基础-08-函数
    Python基础-07-集合
    Python基础-06-字典
  • 原文地址:https://www.cnblogs.com/pekkle/p/10276016.html
Copyright © 2020-2023  润新知