【scala原理系列】scala ArrayOps原理用法示例源码详解
简介
ArrayOps
作为Array
的包装器,提供了所有索引序列中的操作。 在需要时,数组的实例会隐式转换为这个类。
这个类和WrappedArray
的区别在于,调用filter
和map
等转换方法将产生一个数组, 而WrappedArray
将保持为WrappedArray
。
原理
ArrayOps
是Scala中的一个隐式转换类,它是由scala.Array
类自动转换而来的。当我们对一个数组对象调用方法时,Scala编译器会自动将其转换为ArrayOps
类型,以便能够使用更多的操作和方法。
具体来说,ArrayOps
类是通过隐式转换函数wrapIntArray
定义的,该函数接受一个Array[Int]
类型的参数,并返回一个ArrayOps[Int]
类型的对象。在Scala的标准库中,还有其他类似的隐式转换函数,如longArrayOps
、floatArrayOps
等,它们分别用于将数组类型转换为相应的ArrayOps
对象。
通过将数组转换为ArrayOps
对象,我们可以使用ArrayOps
提供的丰富方法和操作符来处理数组,而不仅限于原始的数组操作。这些方法和操作符包括求和、最大值、最小值、排序、复制到另一个数组、切片、转换为其他类型的数组、添加元素、并行操作、展平、转置、拆分等。
总之,ArrayOps
是通过隐式转换实现的,它扩展了数组类型的功能,使得我们可以更方便地对数组进行操作和处理。
隐式转换源码
object Predef extends LowPriorityImplicits with DeprecatedPredef {
implicit def genericArrayOps[T](xs: Array[T]): ArrayOps[T] = (xs match {
case x: Array[AnyRef] => refArrayOps[AnyRef](x)
case x: Array[Boolean] => booleanArrayOps(x)
case x: Array[Byte] => byteArrayOps(x)
case x: Array[Char] => charArrayOps(x)
case x: Array[Double] => doubleArrayOps(x)
case x: Array[Float] => floatArrayOps(x)
case x: Array[Int] => intArrayOps(x)
case x: Array[Long] => longArrayOps(x)
case x: Array[Short] => shortArrayOps(x)
case x: Array[Unit] => unitArrayOps(x)
case null => null
}).asInstanceOf[ArrayOps[T]]
implicit def booleanArrayOps(xs: Array[Boolean]): ArrayOps[Boolean] = new ArrayOps.ofBoolean(xs)
implicit def byteArrayOps(xs: Array[Byte]): ArrayOps[Byte] = new ArrayOps.ofByte(xs)
implicit def charArrayOps(xs: Array[Char]): ArrayOps[Char] = new ArrayOps.ofChar(xs)
implicit def doubleArrayOps(xs: Array[Double]): ArrayOps[Double] = new ArrayOps.ofDouble(xs)
implicit def floatArrayOps(xs: Array[Float]): ArrayOps[Float] = new ArrayOps.ofFloat(xs)
implicit def intArrayOps(xs: Array[Int]): ArrayOps[Int] = new ArrayOps.ofInt(xs)
implicit def longArrayOps(xs: Array[Long]): ArrayOps[Long] = new ArrayOps.ofLong(xs)
implicit def refArrayOps[T <: AnyRef](xs: Array[T]): ArrayOps[T] = new ArrayOps.ofRef[T](xs)
implicit def shortArrayOps(xs: Array[Short]): ArrayOps[Short] = new ArrayOps.ofShort(xs)
implicit def unitArrayOps(xs: Array[Unit]): ArrayOps[Unit] = new ArrayOps.ofUnit(xs)
}
方法总结
方法名 | 描述 |
---|---|
copyToArray | 将当前数组的元素复制到另一个数组中。 |
slice | 对数组进行切片操作,返回指定范围内的子数组。 |
toArray | 将数组转换为另一种类型的数组。 |
:+ | 在数组末尾添加一个元素,并返回一个新的数组。 |
+: | 在数组开头添加一个元素,并返回一个新的数组。 |
par | 将数组转换为并行数组。 |
flatten | 将二维数组展平成一维数组。 |
transpose | 转置二维数组。 |
unzip | 将数组中的元素对拆分成两个数组。 |
unzip3 | 将数组中的元素三元组拆分成三个数组。 |
示例
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
import scala.collection.parallel.mutable.ParArray
object ArrayOpsDemo {
def main(args: Array[String]): Unit = {
// 创建一个整数数组
val array: Array[Int] = Array(1, 2, 3, 4, 5)
// 将数组转换为ArrayOps对象,以便使用ArrayOps的方法
val arrayOps: mutable.ArrayOps[Int] = array
// 使用ArrayOps的方法操作数组
val sum: Int = arrayOps.sum
val max: Int = arrayOps.max
val min: Int = arrayOps.min
val sorted: Array[Int] = arrayOps.sorted
val slicedArray: Array[Int] = arrayOps.slice(1, 4)
val toArray: Array[Any] = arrayOps.toArray[Any]
val appendedArray: Array[Int] = arrayOps.:+(6)
val prependedArray: Array[Int] = arrayOps.+:(0)
val parArray: ParArray[Int] = arrayOps.par
val flattenedArray: Array[Int] = Array(Array(1, 2), Array(3, 4)).flatten
val transposedArray: Array[Array[Int]] = Array(Array(1, 2), Array(3, 4)).transpose
val unzipped: (Array[Int], Array[Int]) = Array((1, 2), (3, 4)).unzip
val unzipped3: (Array[Int], Array[Int], Array[Int]) = Array((1, 2, 3), (4, 5, 6)).unzip3
// 打印结果
println("数组元素之和:" + sum)
println("数组最大值:" + max)
println("数组最小值:" + min)
println("排序后的数组:" + sorted.mkString(", "))
println("切片后的数组:" + slicedArray.mkString(", "))
println("转换为其他类型的数组:" + toArray.mkString(", "))
println("在末尾添加元素后的数组:" + appendedArray.mkString(", "))
println("在开头添加元素后的数组:" + prependedArray.mkString(", "))
println("并行数组:" + parArray.mkString(", "))
println("展平后的数组:" + flattenedArray.mkString(", "))
println("转置后的二维数组:")
transposedArray.foreach(row => println(row.mkString(", ")))
println("拆分后的两个数组:" + unzipped._1.mkString(", ") + ", " + unzipped._2.mkString(", "))
println("拆分后的三个数组:" + unzipped3._1.mkString(", ") + ", " + unzipped3._2.mkString(", ") + ", " + unzipped3._3.mkString(", "))
// 创建一个可变数组
val arrayBuffer: ArrayBuffer[Int] = ArrayBuffer(6, 7, 8, 9, 10)
// 将可变数组转换为ArrayOps对象
var arrayBufferOps: mutable.ArrayOps[Int] = arrayBuffer.toArray
// 使用ArrayOps的方法操作可变数组
arrayBufferOps.foreach(println)
arrayBufferOps = arrayBufferOps :+ 11
arrayBufferOps = 9 +: arrayBufferOps
// 打印修改后的可变数组
println("修改后的可变数组:" + arrayBufferOps.mkString(", "))
}
}
//数组元素之和:15
//数组最大值:5
//数组最小值:1
//排序后的数组:1, 2, 3, 4, 5
//切片后的数组:2, 3, 4
//转换为其他类型的数组:1, 2, 3, 4, 5
//在末尾添加元素后的数组:1, 2, 3, 4, 5, 6
//在开头添加元素后的数组:0, 1, 2, 3, 4, 5
//并行数组:1, 2, 3, 4, 5
//展平后的数组:1, 2, 3, 4
//转置后的二维数组:
//1, 3
//2, 4
//拆分后的两个数组:1, 3, 2, 4
//拆分后的三个数组:1, 4, 2, 5, 3, 6
//6
//7
//8
//9
//10
//修改后的可变数组:9, 6, 7, 8, 9, 10, 11
源码分析
/**
* 这个类作为`Array`的包装器,提供了所有索引序列中的操作。
* 在需要时,数组的实例会隐式转换为这个类。
*
* 这个类和`WrappedArray`的区别在于,调用`filter`和`map`等转换方法将产生一个数组,
* 而`WrappedArray`将保持为`WrappedArray`。
*
* @since 2.8
*
* @tparam T 数组中元素的类型。
*
* @define Coll `Array`
* @define orderDependent
* @define orderDependentFold
* @define mayNotTerminateInf
* @define willNotTerminateInf
*/
sealed trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParallelizable[T, ParArray[T]] {
private def elementClass: Class[_] =
repr.getClass.getComponentType
override def copyToArray[U >: T](xs: Array[U], start: Int, len: Int) {
val l = len min repr.length min (xs.length - start)
if (l > 0) Array.copy(repr, 0, xs, start, l)
}
override def slice(from: Int, until: Int): Array[T] = {
val reprVal = repr
val lo = math.max(from, 0)
val hi = math.min(math.max(until, 0), reprVal.length)
val size = math.max(hi - lo, 0)
val result = java.lang.reflect.Array.newInstance(elementClass, size)
if (size > 0) {
Array.copy(reprVal, lo, result, 0, size)
}
result.asInstanceOf[Array[T]]
}
override def toArray[U >: T : ClassTag]: Array[U] = {
val thatElementClass = implicitly[ClassTag[U]].runtimeClass
if (elementClass eq thatElementClass)
repr.asInstanceOf[Array[U]]
else
super.toArray[U]
}
def :+[B >: T: ClassTag](elem: B): Array[B] = {
val currentLength = repr.length
val result = new Array[B](currentLength + 1)
Array.copy(repr, 0, result, 0, currentLength)
result(currentLength) = elem
result
}
def +:[B >: T: ClassTag](elem: B): Array[B] = {
val currentLength = repr.length
val result = new Array[B](currentLength + 1)
result(0) = elem
Array.copy(repr, 0, result, 1, currentLength)
result
}
override def par = ParArray.handoff(repr)
/** 将二维数组展平,将所有行连接成一个单独的数组。
*
* @tparam U 行元素的类型。
* @param asTrav 将数组中的元素转换为行 - 类型为`U`的数组。
* @return 通过连接该数组的行而获得的数组。
*/
def flatten[U](implicit asTrav: T => scala.collection.Traversable[U], m: ClassTag[U]): Array[U] = {
val b = Array.newBuilder[U]
b.sizeHint(map{case is: scala.collection.IndexedSeq[_] => is.size case _ => 0}.sum)
for (xs <- this)
b ++= asTrav(xs)
b.result()
}
/** 转置一个二维数组。
*
* @tparam U 行元素的类型。
* @param asArray 将数组中的元素转换为行 - 类型为`U`的数组。
* @return 通过替换该数组的元素以表示行获得的数组。
*/
def transpose[U](implicit asArray: T => Array[U]): Array[Array[U]] = {
val bb: Builder[Array[U], Array[Array[U]]] = Array.newBuilder(ClassTag[Array[U]](elementClass))
if (isEmpty) bb.result()
else {
def mkRowBuilder() = Array.newBuilder(ClassTag[U](elementClass.getComponentType))
val bs = asArray(head) map (_ => mkRowBuilder())
for (xs <- this) {
var i = 0
for (x <- asArray(xs)) {
bs(i) += x
i += 1
}
}
for (b <- bs) bb += b.result()
bb.result()
}
}
/** 将一对数组转换为第一个元素数组和第二个元素数组。
*
* @tparam T1 元素对的第一半的类型
* @tparam T2 元素对的第二半的类型
* @param asPair 断言这个数组的元素类型是一对的隐式转换。
* @param ct1 T1类型参数的类标签,用于创建Array[T1]的实例
* @param ct2 T2类型参数的类标签,用于创建Array[T2]的实例
* @return 包含分别是该数组的元素对的第一半和第二半的一对数组。
*/
def unzip[T1, T2](implicit asPair: T => (T1, T2), ct1: ClassTag[T1], ct2: ClassTag[T2]): (Array[T1], Array[T2]) = {
val a1 = new Array[T1](length)
val a2 = new Array[T2](length)
var i = 0
while (i < length) {
val e = apply(i)
a1(i) = e._1
a2(i) = e._2
i += 1
}
(a1, a2)
}
/** 将三元组的数组转换为三个数组,一个包含三元组中每个位置的元素。
*
* @tparam T1 三元组中第一个元素的类型
* @tparam T2 三元组中第二个元素的类型
* @tparam T3 三元组中第三个元素的类型
* @param asTriple 断言这个数组的元素类型是三元组的隐式转换。
* @param ct1 T1类型参数的类标签,用于创建Array[T1]的实例
* @param ct2 T2类型参数的类标签,用于创建Array[T2]的实例
* @param ct3 T3类型参数的类标签,用于创建Array[T3]的实例
* @return 一个由该数组的每个元素三元组的第一、第二和第三个元素组成的三个数组。
*/
def unzip3[T1, T2, T3](implicit asTriple: T => (T1, T2, T3), ct1: ClassTag[T1], ct2: ClassTag[T2],
ct3: ClassTag[T3]): (Array[T1], Array[T2], Array[T3]) = {
val a1 = new Array[T1](length)
val a2 = new Array[T2](length)
val a3 = new Array[T3](length)
var i = 0
while (i < length) {
val e = apply(i)
a1(i) = e._1
a2(i) = e._2
a3(i) = e._3
i += 1
}
(a1, a2, a3)
}
def seq = thisCollection
}
/**
* `ArrayOps`的伴生对象。
*
* @since 2.8
*/
object ArrayOps {
/** 包含引用类型的数组的`ArrayOps`类。 */
final class ofRef[T <: AnyRef](override val repr: Array[T]) extends AnyVal with ArrayOps[T] with ArrayLike[T, Array[T]] {
override protected[this] def thisCollection: WrappedArray[T] = new WrappedArray.ofRef[T](repr)
override protected[this] def toCollection(repr: Array[T]): WrappedArray[T] = new WrappedArray.ofRef[T](repr)
override protected[this] def newBuilder = new ArrayBuilder.ofRef[T]()(ClassTag[T](repr.getClass.getComponentType))
def length: Int = repr.length
def apply(index: Int): T = repr(index)
def update(index: Int, elem: T) { repr(index) = elem }
}
/** 包含`Byte`的数组的`ArrayOps`的子类。 */
final class ofByte(override val repr: Array[Byte]) extends AnyVal with ArrayOps[Byte] with ArrayLike[Byte, Array[Byte]] {
override protected[this] def thisCollection: WrappedArray[Byte] = new WrappedArray.ofByte(repr)
override protected[this] def toCollection(repr: Array[Byte]): WrappedArray[Byte] = new WrappedArray.ofByte(repr)
override protected[this] def newBuilder = new ArrayBuilder.ofByte
def length: Int = repr.length
def apply(index: Int): Byte = repr(index)
def update(index: Int, elem: Byte) { repr(index) = elem }
}
/** 包含`Short`的数组的`ArrayOps`的子类。 */
final class ofShort(override val repr: Array[Short]) extends AnyVal with ArrayOps[Short] with ArrayLike[Short, Array[Short]] {
override protected[this] def thisCollection: WrappedArray[Short] = new WrappedArray.ofShort(repr)
override protected[this] def toCollection(repr: Array[Short]): WrappedArray[Short] = new WrappedArray.ofShort(repr)
override protected[this] def newBuilder = new ArrayBuilder.ofShort
def length: Int = repr.length
def apply(index: Int): Short = repr(index)
def update(index: Int, elem: Short) { repr(index) = elem }
}
/** 包含`Char`的数组的`ArrayOps`的子类。 */
final class ofChar(override val repr: Array[Char]) extends AnyVal with ArrayOps[Char] with ArrayLike[Char, Array[Char]] {
override protected[this] def thisCollection: WrappedArray[Char] = new WrappedArray.ofChar(repr)
override protected[this] def toCollection(repr: Array[Char]): WrappedArray[Char] = new WrappedArray.ofChar(repr)
override protected[this] def newBuilder = new ArrayBuilder.ofChar
def length: Int = repr.length
def apply(index: Int): Char = repr(index)
def update(index: Int, elem: Char) { repr(index) = elem }
}
/** 包含`Int`的数组的`ArrayOps`的子类。 */
final class ofInt(override val repr: Array[Int]) extends AnyVal with ArrayOps[Int] with ArrayLike[Int, Array[Int]] {
override protected[this] def thisCollection: WrappedArray[Int] = new WrappedArray.ofInt(repr)
override protected[this] def toCollection(repr: Array[Int]): WrappedArray[Int] = new WrappedArray.ofInt(repr)
override protected[this] def newBuilder = new ArrayBuilder.ofInt
def length: Int = repr.length
def apply(index: Int): Int = repr(index)
def update(index: Int, elem: Int) { repr(index) = elem }
}
/** 包含`Long`的数组的`ArrayOps`的子类。 */
final class ofLong(override val repr: Array[Long]) extends AnyVal with ArrayOps[Long] with ArrayLike[Long, Array[Long]] {
override protected[this] def thisCollection: WrappedArray[Long] = new WrappedArray.ofLong(repr)
override protected[this] def toCollection(repr: Array[Long]): WrappedArray[Long] = new WrappedArray.ofLong(repr)
override protected[this] def newBuilder = new ArrayBuilder.ofLong
def length: Int = repr.length
def apply(index: Int): Long = repr(index)
def update(index: Int, elem: Long) { repr(index) = elem }
}
/** 包含`Float`的数组的`ArrayOps`的子类。 */
final class ofFloat(override val repr: Array[Float]) extends AnyVal with ArrayOps[Float] with ArrayLike[Float, Array[Float]] {
override protected[this] def thisCollection: WrappedArray[Float] = new WrappedArray.ofFloat(repr)
override protected[this] def toCollection(repr: Array[Float]): WrappedArray[Float] = new WrappedArray.ofFloat(repr)
override protected[this] def newBuilder = new ArrayBuilder.ofFloat
def length: Int = repr.length
def apply(index: Int): Float = repr(index)
def update(index: Int, elem: Float) { repr(index) = elem }
}
/** 包含`Double`的数组的`ArrayOps`的子类。 */
final class ofDouble(override val repr: Array[Double]) extends AnyVal with ArrayOps[Double] with ArrayLike[Double, Array[Double]] {
override protected[this] def thisCollection: WrappedArray[Double] = new WrappedArray.ofDouble(repr)
override protected[this] def toCollection(repr: Array[Double]): WrappedArray[Double] = new WrappedArray.ofDouble(repr)
override protected[this] def newBuilder = new ArrayBuilder.ofDouble
def length: Int = repr.length
def apply(index: Int): Double = repr(index)
def update(index: Int, elem: Double) { repr(index) = elem }
}
/** 包含`Boolean`的数组的`ArrayOps`的子类。 */
final class ofBoolean(override val repr: Array[Boolean]) extends AnyVal with ArrayOps[Boolean] with ArrayLike[Boolean, Array[Boolean]] {
override protected[this] def thisCollection: WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr)
override protected[this] def toCollection(repr: Array[Boolean]): WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr)
override protected[this] def newBuilder = new ArrayBuilder.ofBoolean
def length: Int = repr.length
def apply(index: Int): Boolean = repr(index)
def update(index: Int, elem: Boolean) { repr(index) = elem }
}
/** 包含`Unit`类型的数组的`ArrayOps`的子类。 */
final class ofUnit(override val repr: Array[Unit]) extends AnyVal with ArrayOps[Unit] with ArrayLike[Unit, Array[Unit]] {
override protected[this] def thisCollection: WrappedArray[Unit] = new WrappedArray.ofUnit(repr)
override protected[this] def toCollection(repr: Array[Unit]): WrappedArray[Unit] = new WrappedArray.ofUnit(repr)
override protected[this] def newBuilder = new ArrayBuilder.ofUnit
def length: Int = repr.length
def apply(index: Int): Unit = repr(index)
def update(index: Int, elem: Unit) { repr(index) = elem }
}
}
override protected[this] def thisCollection: WrappedArray[Unit] = new WrappedArray.ofUnit(repr)
override protected[this] def toCollection(repr: Array[Unit]): WrappedArray[Unit] = new WrappedArray.ofUnit(repr)
override protected[this] def newBuilder = new ArrayBuilder.ofUnit
def length: Int = repr.length
def apply(index: Int): Unit = repr(index)
def update(index: Int, elem: Unit) { repr(index) = elem }
}
}