Arrays and Lists
Outline Collections Arrays vs. Lists Functions using Arrays/Lists Higher order functions using Arrays/Lists
Collections We've seen tuples to store multiple objects together, but the tuple syntax of._# is awkward and doesn't scale. Collection types solve this problem in Scala. The 2 basic collection types are Arrays and Lists The Array and the List are referred as sequence. That means that they store a number of different values in a specific order that you can get to the elements in them by an integer index. These differ in the way they are laid out in memory (and thus their efficiency for different problems), but many of the same methods are used for both; and many problems are solvable by both.
Arrays
Array Contiguous, Ordered, Rigidly structured Syntax: val arr = Array(12, 0, 31, 14) arr(0) //12 arr(2) //31 Arrays are mutable: arr(1) = 27 //arr now equals [12, 27, 31, 14] ++ joins arrays together
Lists
Lists Non-contiguous, Ordered, Flexible Syntax: val lst = List(12, 0, 31, 14) lst(0) //12 lst(2) //31 Lists are immutable: lst(1) = 27 //ERROR But new, longer/shorter lists are easily created: val newlst = 1 :: lst //[1,12,0,31,14] :: is the cons operator ::: joins lists together
www.scala-lang.org/api
Exercise: array operations val a = new Array[Int](5) val b = new Array[Boolean](10) val c = Array(1,2,3,4) a(2) b(5) c(0) a.length b.length c.length val d = a ++ c d.length
Exercise: List operations val lstofchars = List('a','b','c') val lstofints1 = List(1,2,3,4) val lstofints2 = List(5,6,7,8) lstofchars(1) // b lstofints1(0) // 1 lstofints2(0) // 5 lstofchars.length // 3 val onemore = 42 :: lstofints1 // List(42,1,2,3,4) val combined = lstofints1 ::: lstofints2 val conslist = 20 :: 21 :: 22 :: 23 :: Nil conslist.length // 4 conslist(3) // 23
Array vs List
Parametric Types List[Int] Array[Boolean]
Functions using arrays Arrays are objects, and can be arguments/parameters to functions, as well as return values Recursion can be useful to create functions/procedures that operate on arrays, typically by passing an "index" value as an additional argument to the function
fillarray fillarray - initialize each element of an array to be the value of a series def fillarray(arr:array[int],index:int):unit = { if(index<arr.length) { arr(index)=readint() fillarray(arr,index+1) } } This function does not return a result. The fact that Arrays are mutable means that we can pass in an array and have the function mutate the contents. As a result, nothing needs to be returned.
operateonarray operateonarray - combine array elements together using a specified function def operateonarray(arr:array[int],index:int,func:(int,int)=>int):int={ if(index<arr.length-1) { func(arr(index),operateonarray(arr,index+1,func))} else { arr(arr.length-1)} }
Functions on Lists Lists are objects, and can be arguments to functions, parameter of functions, as well as return values Recursion can be useful to create functions/procedures that operate on lists; unlike Arrays, recursion over lists typically involves two list methods:.head -- returns the first element in a list; for a List[A] this return value is of the type A.tail -- returns the rest of the list after the 1st element; for a List[A] this return value is also a List[A]
inputlist - make a list from user inputs def inputlist():list[int] = { val in = readline if (in== quit ) Nil else in.toint :: inputlist() }
operateonlist - combine list elements together using a specified function def operateonlist(lst:list[int],func:(int,int)=>int):int = { if(lst.tail==nil) lst.head else func(lst.head,operateonlist(lst.tail,func)) }
Standard Methods for Array/List/Collections isempty reverse slice(from:int, until:int) splitat(ind:int) take(n:int) sum, min, max contains(elem:any) mkstring and many more
Higher-order methods Creating Array/List fill(size)(pass_by_name_variable) tabulate(size)(f: Int=>B) When you already have an array/list map(f:(a)=>b) filter(p:(a)=>boolean) foreach(f:(a)=>unit) forall(p(a)=>boolean) reduceleft(f:(a,a)=>a) reduceright(f:(a,a)=>a) and many more
Fill val a = Array.fill(5)(1) //currying and pass_by_name variable val b = Array.fill(10)("Hello") val c = List.fill(5)(math.random) val d = Array.fill(3)(readInt) var i=1 val j = List.fill(5){ i*=2; i } //List(2, 4, 8, 16, 32)
Tabulate The tabulate method creates a new list or array filling each element with its index that has a function that you supply applied to it. val e = Array.tabulate(3)((x:Int)=>x) val f = Array.tabulate(12)((x:Int)=>x.toString*2) val g = Array.tabulate(4)((x:Int)=>(x>2)) val h = List.tabulate(5)((_:Int)*2) val i = List.tabulate(100)((z:Int)=>z.toString)
Map The map method takes a function that operates on an element and results in something. It produces a new collection that contains the results of applying that function to all the contents of the original collection. val j = List(1, 2, 3, 4) j.map(_ + 1) j.map(_ * 2) j.map(i => i * i)
Filter The filter method takes a function that will operate on an element and result in a Boolean. Produces a new collection that contains only the elements for which the function is true. val k = List(1, 2, 3, 4) k.filter(_ < 3) k.filter(x => x>=4 && x<=7) k.filter(_ % 2 == 0)
Foreach and forall foreach(f:(a)=>unit) takes a function that operates on an element and applies it to all elements in the collection. The result type is Unit. This method is called only for the side effects. forall(p:(a)=>boolean) takes a function that will operate on an element and result in a Boolean. Its value is true if the function is true for all elements of the collection. val l = List(1, 2, 3, 4) l.foreach(println) l.forall(_ > 0) //true l.forall(_ > 4) //false
Reduce val m = List(7,4,6,3,9,1) m.reduceleft(_ + _) // Means 7+4+6+3+9+1 m.reduceleft(_ * _) // Means 7*4*6*3*9*1 m.reduceleft(_ - _) // Means 7-4-6-3-9-1 m.reduceright(_ - _) // Means 7-(4-(6-(3-(9-1))))
Aliasing val a = Array(1,2,3,4) val b = a b(1) = 42 //This changed both a & b //because b is an "alias" of a
Cloning val a = Array(1,2,3,4) val b = a b(1) = 42 //This changed both a & b //because b is an "alias" of a val c = a.clone c(1) = 27 //This changes only c
Exercise Suppose a is an Array[String]; write statement that prints elements of a, one on each line val a = Array( 3, 5, 6 ) convert elements of the array to integers, then compute sum a.map( ).reduceleft( )
One-dimensional arrays Two ways to create 1-d arrays. //New, empty arrays. Automatically initialized to ZERO. syntax: new Array[T](#) val x = new Array[Int](10)//ZERO means 0. val y = new Array[String](5)// ZERO means null. //New and Initialized arrays val z = Array.fill(10)( ) val w = Array.tabulate(10)(x=>3*x*x)
Multi-dimensional Arrays Several syntax options: Array(Array(1,2), Array(3,4)) //New, empty arrays val a = new Array[Array[Int]](4) for(i <- 0 until 4) a(i) = new Array[Int](10) val b = Array.ofDim[Int](2,3,4) //Initialized arrays val c = Array.fill(2,4)( ) val d = Array.tabulate(2,3)((x,y)=>f(x,y))