Scala中Array和List的区别说明

 更新时间:2021年10月11日 09:00:59   作者:power0405hf  
这篇文章主要介绍了Scala中Array和List的区别说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

Scala Array和List的区别

Difference between Array and List in scala

Q:什么时候用Array(Buffer)和List(Buffer)?

A:Scala中的List是不可变的递归数据(immutable recursive data),是Scala中的一种基础结构,你应该多用List而不是Array(Array实际上是mutable,不可变(immutable)的Array是IndexedSeq)

Mutable Structures

ListBuffer提供一个常数时间的转换到List。

一个Scala的Array应该是由Java array生成的,因此一个Array[Int]也许比List[Int]更有效率。

但是,我认为Scala中数组尽量少用,因为它感觉是你真的需要知道底层发生了什么,来决定是否Array将所需的基本数据类型进行备份,或者可能boxed as a wrapper type.

Performance differences Array List
Access the ith element O(1) O(i)
Discard the ith element O(n) O(i)
Insert an element at i O(n) O(i)
Reverse O(n) O(n)
Concatenate (length m,n) O(n+m) O(n)
Calculate the length O(1) O(n)
memory differences Array List
Get the first i elements O(i) O(i)
Drop the first i elements O(n-i) O(1)
Insert an element at i O(n) O(i)
Reverse O(n) O(n)
Concatenate (length m,n) O(n+m) O(n)

所以,除非你需要快速随机访问或需要count batches of elements,否则,列表比数组更好。

Scala快排List和Array数组效率实测

代码

package com.tingfeng.scala.test
import scala.annotation.tailrec
import scala.util.{Random, Sorting}
/**
  * 快速排序测试
  */
object SortTest {
  /**
    * 初始化一个数组,产生随机数字填充
    * @param size
    * @return
    */
  def initRandomList(size :Int):List[Int]={
    val random = new Random()
    def initList(size :Int,random: Random):List[Int] = size match {
      case 0 => Nil
      case 1 => List(random.nextInt())
      case s:Int =>
        val value = s / 2
        if( s % 2 == 0) {
          initList(value,random) ++ initList(value,random)
        }else{
          initList(value,random) ++ initList(value + 1,random)
        }
    }
    initList(size,random)
  }
  /**
    * 打印出使用的时间
    * @param call
    */
  def printTime(call : => Unit,tag: String = ""){
    val startTime = System.currentTimeMillis()
    println(tag)
    call
    println
    println(s"use time : ${System.currentTimeMillis() - startTime}\n")
  }
  /**
    * 交换数组中两个位置的值,经过测试这种按位与的方式比普通建立变量交换的效率更高
    * @param array
    * @param x
    * @param y
    */
  def swap(array: Array[Int],x:Int,y:Int):Unit ={
      val t = array(x) ^ array(y)
      array(x) = t ^ array(x)
      array(y) = t ^ array(y)
  }
  /**
    * 将传入的值直接返回,并且执行逻辑
    * @param call
    * @param any
    * @tparam A
    */
  def doThing[A<:Any](any: A,call: A => Unit):A = {
      call(any)
      any
  }
  /**
    * 打印列表
    */
  def printList[A<%Seq[Any]](seq:A,size :Int = 10):Unit={
    seq.splitAt(size)._1.foreach(it => print(s"$it,"))
  }
  def shuffleIntSeq(seq: Array[Int],size: Int):Unit={
      val random = new Random()
      val maxSize = size/2
      for(i <- 0 to maxSize){
          swap(seq,i,maxSize + random.nextInt(maxSize))
      }
  }
  def main(args: Array[String]): Unit = {
    val size = 5000000
    val printSize = 10
    val list = initRandomList(size)
    //打印出钱100个,和List快速排序的时间花费
    printTime(printList[List[Int]](qSortList(list),Math.min(10,size)),"qSortList")
    val array = list.toArray
    printTime(printList[Array[Int]](doThing[Array[Int]](array,Sorting.quickSort),Math.min(printSize,size)),"Sorting.quickSort")
    shuffleIntSeq(array,size)
    printTime(printList[Array[Int]](doThing[Array[Int]](array,qSortArray1),Math.min(printSize,size)),"qSortArray1")
    shuffleIntSeq(array,size)
    printTime(printList[Array[Int]](doThing[Array[Int]](array,qSortArray2),Math.min(printSize,size)),"qSortArray2")
    shuffleIntSeq(array,size)
    printTime(printList[Array[Int]](doThing[Array[Int]](array,qSortArray3),Math.min(printSize,size)),"qSortArray3")
    shuffleIntSeq(array,size)
    printTime(printList[Array[Int]](doThing[Array[Int]](array,qSortArray4),Math.min(printSize,size)),"qSortArray4")
  }
  /**
    * 对List快速排序
    * @param list
    * @return
    */
  def qSortList(list: List[Int]):List[Int] = list match {
    case Nil => Nil
    case head :: other =>
      val (left, right) = other.partition(_ < head)
      (qSortList(left) :+ head) ++ qSortList(right)
  }
  /**
    * 通过每次比较数组‘head'值与其余值的方式直接实现
    * 比‘head'小的值移动到其前,比‘head'大的移动到其之后
    * @param array
    */
  def qSortArray1(array: Array[Int]):Unit = {
    def sort(ay : Array[Int],start: Int,end: Int):Unit={
      if(start >= end) {
        return
      }
      val head = ay(start)
      var spliteIndex = start
      for (i <- start + 1 to end){
        if(ay(i) < head){
          swap(array,spliteIndex,i)
          spliteIndex += 1
        }
      }
      if(start != spliteIndex){
        sort(ay, start, spliteIndex)
      }
      if(start == spliteIndex){
        spliteIndex += 1
      }
      if(spliteIndex != end){
        sort(ay, spliteIndex, end)
      }
    }
    sort(array,0,array.size - 1)
  }
  /**
    * 将数据以中线拆分左右两部分,交换值,使得右边值比左边大,
    * 再以左或者右边交换的界限分为两部分做递归
    * @param array
    */
  def qSortArray2(array: Array[Int]) {
    def sort(l: Int, r: Int) {
      val pivot = array((l + r) / 2)
      var lv = l; var rv = r
      while (lv <= rv) {
        while (array(lv) < pivot) lv += 1
        while (array(rv) > pivot) rv -= 1
        if (lv <= rv) {
          swap(array,lv, rv)
          lv += 1
          rv -= 1
        }
      }
      if (l < rv) sort(l, rv)
      if (rv < r) sort(lv, r)
    }
    sort(0, array.length - 1)
  }
  /**
    * 系统自带的过滤函数,无法排序成功,因为filter返回的是引用
    * @param xs
    * @return
    */
  def qSortArray3(xs: Array[Int]): Array[Int] ={
    if (xs.length <= 1){
      xs
    }else {
      val pivot = xs(xs.length / 2)
      val left = xs filter (pivot > _)
      val cu = xs filter (pivot == _ )
      val right = xs filter (pivot < _ )
      Array.concat(
        qSortArray3(left),cu,qSortArray3(right))
    }
  }
  /**
    * 系统自带的分割函数,无法排序成功,因为partition返回的是引用,数据量大的时候会栈溢出失败
    * @param xs
    * @return
    */
  def qSortArray4(array: Array[Int]): Array[Int] ={
    if (array.length <= 1){
      array
    }else {
      val head = array(0)
      val (left,right) = array.tail partition  (_ < head )
      Array.concat(qSortArray4(left),Array(head),qSortArray4(right))
    }
  }
}

测试结果

qSortList
-2147483293,-2147483096,-2147481318,-2147480959,-2147479572,-2147479284,-2147478285,-2147477579,-2147476191,-2147475936,
use time : 28808

Sorting.quickSort
-2147483293,-2147483096,-2147481318,-2147480959,-2147479572,-2147479284,-2147478285,-2147477579,-2147476191,-2147475936,
use time : 773

qSortArray1
-2147483293,-2147483096,-2147481318,-2147480959,-2147479572,-2147479284,-2147478285,-2147477579,-2147476191,-2147475936,
use time : 1335

qSortArray2
-2147483293,-2147483096,-2147481318,-2147480959,-2147479572,-2147479284,-2147478285,-2147477579,-2147476191,-2147475936,
use time : 629

qSortArray3
508128328,554399267,876118465,968407914,1274954088,1550124974,296879812,2125832312,1874291320,965362519,
use time : 10617

qSortArray4
865409973,-645195021,-735017922,-1893119148,1838343395,1038029591,-560471115,-182627393,-228613831,220531987,
use time : 6904


Process finished with exit code 0

环境:版本Scala2.12.6 , win10 ,ryzen5 1600 , 8G

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • IDEA查看Scala的源码的教程图解

    IDEA查看Scala的源码的教程图解

    这篇文章主要介绍了IDEA查看Scala的源码的方法,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08
  • springboot整合xxl-job的示例代码

    springboot整合xxl-job的示例代码

    这篇文章主要介绍了springboot整合xxl-job的示例代码,主要分为三大模块,分别是调度中心、执行器和配置定时任务的过程,本文给大家介绍的非常详细,需要的朋友可以参考下
    2022-06-06
  • springboot配置Jackson返回统一默认值的实现示例

    springboot配置Jackson返回统一默认值的实现示例

    在项目开发中,我们返回的数据或者对象没有的时候一般直接返回的null,那么如何返回统一默认值,感兴趣的可以了解一下
    2021-07-07
  • 剑指Offer之Java算法习题精讲二叉树专项解析

    剑指Offer之Java算法习题精讲二叉树专项解析

    跟着思路走,之后从简单题入手,反复去看,做过之后可能会忘记,之后再做一次,记不住就反复做,反复寻求思路和规律,慢慢积累就会发现质的变化
    2022-03-03
  • IDEA maven项目依赖无法解析问题

    IDEA maven项目依赖无法解析问题

    这篇文章主要介绍了IDEA maven项目依赖无法解析问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • SpringBoot参数校验与国际化使用教程

    SpringBoot参数校验与国际化使用教程

    这篇文章主要给大家介绍了关于SpringBoot参数校验与国际化使用教程的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • ScrollView中嵌入ListView只显示一条的解决办法

    ScrollView中嵌入ListView只显示一条的解决办法

    在ScrollView添加一个ListView会导致listview控件显示不全,通常只会显示一条,究竟是什么原因呢?下面脚本之家小编给大家介绍ScrollView中嵌入ListView只显示一条的解决办法,感兴趣的朋友一起学习吧
    2016-05-05
  • 浅谈Spring6中的反射机制

    浅谈Spring6中的反射机制

    Java反射机制是Java语言中一种动态(运行时)访问、检测、修改它本身的能力,主要作用是动态(运行时)获取类的完整结构信息、调用对象的方法,需要的朋友可以参考下
    2023-05-05
  • Mybatis不启动项目直接测试Mapper的实现方法

    Mybatis不启动项目直接测试Mapper的实现方法

    在项目开发中,测试单个Mybatis Mapper方法通常需要启动整个SpringBoot项目,消耗大量时间,本文介绍通过Main方法和Mybatis配置类,快速测试Mapper功能,无需启动整个项目,这方法使用AnnotationConfigApplicationContext容器
    2024-09-09
  • Java Spring事务使用及验证过程详解

    Java Spring事务使用及验证过程详解

    这篇文章主要介绍了Java Spring事务使用及验证过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-12-12

最新评论