I'm new to Scala ,just started learning it today.I would like to know how to initialize an array in Scala.
Example Java code
String[] arr = { "Hello", "World" };
What is the equivalent of the above code in Scala ?
scala> val arr = Array("Hello","World")
arr: Array[java.lang.String] = Array(Hello, World)
To initialize an array filled with zeros, you can use:
> Array.fill[Byte](5)(0)
Array(0, 0, 0, 0, 0)
This is equivalent to Java's new byte[5].
Can also do more dynamic inits with fill, e.g.
Array.fill(10){scala.util.Random.nextInt(5)}
==>
Array[Int] = Array(0, 1, 0, 0, 3, 2, 4, 1, 4, 3)
Additional to Vasil's answer: If you have the values given as a Scala collection, you can write
val list = List(1,2,3,4,5)
val arr = Array[Int](list:_*)
println(arr.mkString)
But usually the toArray method is more handy:
val list = List(1,2,3,4,5)
val arr = list.toArray
println(arr.mkString)
If you know Array's length but you don't know its content, you can use
val length = 5
val temp = Array.ofDim[String](length)
If you want to have two dimensions array but you don't know its content, you can use
val row = 5
val column = 3
val temp = Array.ofDim[String](row, column)
Of course, you can change String to other type.
If you already know its content, you can use
val temp = Array("a", "b")
Another way of declaring multi-dimentional arrays:
Array.fill(4,3)("")
res3: Array[Array[String]] = Array(Array("", "", ""), Array("", "", ""),Array("", "", ""), Array("", "", ""))
[Consolidating all the answers]
Initializing 1-D Arrays
// With fixed values
val arr = Array("a", "ab", "c")
// With zero value of the type
val size = 13
val arrWithZeroVal = Array.ofDim[Int](size) //values = 0
val arrBoolWithZeroVal = Array.ofDim[Boolean](size) //values = false
// With default value
val defVal = -1
val arrWithDefVals = Array.fill[Int](size)(defVal)
//With random values
val rand = scala.util.Random
def randomNumberGen: Int = rand.nextInt(5)
val arrWithRandomVals = Array.fill[Int](size){randomNumberGen}
Initializing 2-D/3-D/n-D Arrays
// With zero value of the type
val arr3dWithZeroVal = Array.ofDim[Int](5, 4, 3)
// With default value
val defVal = -1
val arr3dWithDefVal = Array.fill[Int](5, 4, 3)(defVal)
//With random values
val arr3dWithRandomValv = Array.fill[Int](5, 4, 3){randomNumberGen}
Conclusion :
Use Array.ofDim[TYPE](d1, d2, d3...) to use zero value of the type.
Use Array.fill[TYPE](d1, d2, d3...)(functionWhichReturnsTYPE) otherwise
Output for reference :
scala> val arr = Array("a", "ab", "c")
arr: Array[String] = Array(a, ab, c)
scala> val size = 13
size: Int = 13
scala> val arrWithZeroVal = Array.ofDim[Int](size) //values = 0
arrWithZeroVal: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
scala> val arrBoolWithZeroVal = Array.ofDim[Boolean](size) //values = false
arrBoolWithZeroVal: Array[Boolean] = Array(false, false, false, false, false, false, false, false, false, false, false, false, false)
scala> val defVal = -1
defVal: Int = -1
scala> val arrWithDefVals = Array.fill[Int](size)(defVal)
arrWithDefVals: Array[Int] = Array(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
scala> val rand = scala.util.Random
rand: util.Random.type = scala.util.Random$#6e3dd5ce
scala> def randomNumberGen: Int = rand.nextInt(5)
randomNumberGen: Int
scala> val arrWithRandomVals = Array.fill[Int](size){randomNumberGen}
arrWithRandomVals: Array[Int] = Array(2, 2, 3, 1, 1, 3, 3, 3, 2, 3, 2, 2, 0)
scala> val arr3dWithZeroVal = Array.ofDim[Int](5, 4, 3)
arr3dWithZeroVal: Array[Array[Array[Int]]] = Array(Array(Array(0, 0, 0), Array(0, 0, 0), Array(0, 0, 0), Array(0, 0, 0)), Array(Array(0, 0, 0), Array(0, 0, 0), Array(0, 0, 0), Array(0, 0, 0)), Array(Array(0, 0, 0), Array(0, 0, 0), Array(0, 0, 0), Array(0, 0, 0)), Array(Array(0, 0, 0), Array(0, 0, 0), Array(0, 0, 0), Array(0, 0, 0)), Array(Array(0, 0, 0), Array(0, 0, 0), Array(0, 0, 0), Array(0, 0, 0)))
scala> val arr3dWithDefVal = Array.fill[Int](5, 4, 3)(defVal)
arr3dWithDefVal: Array[Array[Array[Int]]] = Array(Array(Array(-1, -1, -1), Array(-1, -1, -1), Array(-1, -1, -1), Array(-1, -1, -1)), Array(Array(-1, -1, -1), Array(-1, -1, -1), Array(-1, -1, -1), Array(-1, -1, -1)), Array(Array(-1, -1, -1), Array(-1, -1, -1), Array(-1, -1, -1), Array(-1, -1, -1)), Array(Array(-1, -1, -1), Array(-1, -1, -1), Array(-1, -1, -1), Array(-1, -1, -1)), Array(Array(-1, -1, -1), Array(-1, -1, -1), Array(-1, -1, -1), Array(-1, -1, -1)))
scala> val arr3dWithRandomVals = Array.fill[Int](5, 4, 3){randomNumberGen}
arr3dWithRandomVals: Array[Array[Array[Int]]] = Array(Array(Array(2, 0, 0), Array(4, 1, 0), Array(4, 0, 0), Array(0, 0, 1)), Array(Array(0, 1, 2), Array(2, 0, 2), Array(0, 4, 2), Array(0, 4, 2)), Array(Array(4, 3, 0), Array(2, 2, 4), Array(4, 0, 4), Array(4, 2, 1)), Array(Array(0, 3, 3), Array(0, 0, 4), Array(4, 1, 3), Array(2, 2, 3)), Array(Array(0, 2, 3), Array(1, 4, 1), Array(1, 3, 3), Array(0, 0, 3)))
Related
I know this is a lengthy question :) I'm trying to implement Hamiltonian Cycle on a dataset in Scala 2.11, as part of this I'm trying to generate Adjacency matrix from a Map of values.
Explanation:
Keys 0 to 4 are the different cities, so in below "allRoads" Variable
0 -> Set(1, 2) Means city0 is connected to city1 and city2
1 -> Set(0, 2, 3, 4) Means City1 is connected to city0,city2,city3,city4
.
.
I need to generate adj Matrix, for E.g:
I need to generate 1 if the city is connected, or else I've to generate 0, meaning
for: "0 -> Set(1, 2)", I need to generate: Map(0 -> Array(0,1,1,0,0))
input-
var allRoads = Map(0 -> Set(1, 2), 1 -> Set(0, 2, 3, 4), 2 -> Set(0, 1, 3, 4), 3 -> Set(2, 4, 1), 4 -> Set(2, 3, 1))
My Code:
val n: Int = 5
val listOfCities = (0 to n-1).toList
var allRoads = Map(0 -> Set(1, 2), 1 -> Set(0, 2, 3, 4), 2 -> Set(0, 1, 3, 4), 3 -> Set(2, 4, 1), 4 -> Set(2, 3, 1))
var adjmat:Array[Int] = Map()
for( i <- 0 until allRoads.size;j <- listOfCities) {
allRoads.get(i) match {
case Some(elem) => if (elem.contains(j)) adjmat = adjmat:+1 else adjmat = adjmat :+0
case _ => None
}
}
which outputs:
output: Array[Int] = Array(0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0)
Expected output - Something like this, please suggest if there's something better to generate input to Hamiltonian Cycle
Map(0 -> Array(0, 1, 1, 0, 0),1 -> Array(1, 0, 1, 1, 1),2 -> Array(1, 1, 0, 1, 1),3 -> Array(0, 1, 1, 0, 1),4 -> Array(0, 1, 1, 1, 0))
Not sure how to store the above output as a Map or a Plain 2D Array.
Try
val cities = listOfCities.toSet
allRoads.map { case (city, roads) =>
city -> listOfCities.map(city => if ((cities diff roads).contains(city)) 0 else 1)
}
which outputs
Map(0 -> List(0, 1, 1, 0, 0), 1 -> List(1, 0, 1, 1, 1), 2 -> List(1, 1, 0, 1, 1), 3 -> List(0, 1, 1, 0, 1), 4 -> List(0, 1, 1, 1, 0))
Let's say I have a sequence of ints like this:
val mySeq = Seq(0, 1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
I want to split this by let's say 0 as a delimiter to look like this:
val mySplitSeq = Seq(Seq(0, 1, 2, 1), Seq(0, -1), Seq(0, 1, 2, 3, 2))
What is the most elegant way to do this in Scala?
This works alright
mySeq.foldLeft(Vector.empty[Vector[Int]]) {
case (acc, i) if acc.isEmpty => Vector(Vector(i))
case (acc, 0) => acc :+ Vector(0)
case (acc, i) => acc.init :+ (acc.last :+ i)
}
where 0 (or whatever) is your delimiter.
Efficient O(n) solution
Tail-recursive solution that never appends anything to lists:
def splitBy[A](sep: A, seq: List[A]): List[List[A]] = {
#annotation.tailrec
def rec(xs: List[A], revAcc: List[List[A]]): List[List[A]] = xs match {
case Nil => revAcc.reverse
case h :: t =>
if (h == sep) {
val (pref, suff) = xs.tail.span(_ != sep)
rec(suff, (h :: pref) :: revAcc)
} else {
val (pref, suff) = xs.span(_ != sep)
rec(suff, pref :: revAcc)
}
}
rec(seq, Nil)
}
val mySeq = List(0, 1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
println(splitBy(0, mySeq))
produces:
List(List(0, 1, 2, 1), List(0, -1), List(0, 1, 2, 3, 2))
It also handles the case where the input does not start with the separator.
For fun: Another O(n) solution that works for small integers
This is more of warning rather than a solution. Trying to reuse String's split does not result in anything sane:
val mySeq = Seq(0, 1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
val z = mySeq.min
val res = (mySeq
.map(x => (x - z).toChar)
.mkString
.split((-z).toChar)
.map(s => 0 :: s.toList.map(_.toInt + z)
).toList.tail)
It will fail if the integers span a range larger than 65535, and it looks pretty insane. Nevertheless, I find it amusing that it works at all:
res: List[List[Int]] = List(List(0, 1, 2, 1), List(0, -1), List(0, 1, 2, 3, 2))
You can use foldLeft:
val delimiter = 0
val res = mySeq.foldLeft(Seq[Seq[Int]]()) {
case (acc, `delimiter`) => acc :+ Seq(delimiter)
case (acc, v) => acc.init :+ (acc.last :+ v)
}
NOTE: This assumes input necessarily starts with delimiter.
One more variant using indices and reverse slicing
scala> val s = Seq(0,1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
s: scala.collection.mutable.Seq[Int] = ArrayBuffer(0, 1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
scala> s.indices.filter( s(_)==0).+:(if(s(0)!=0) -1 else -2).filter(_>= -1 ).reverse.map( {var p=0; x=>{ val y=s.slice(x,s.size-p);p=s.size-x;y}}).reverse
res173: scala.collection.immutable.IndexedSeq[scala.collection.mutable.Seq[Int]] = Vector(ArrayBuffer(0, 1, 2, 1), ArrayBuffer(0, -1), ArrayBuffer(0, 1, 2, 3, 2))
if the starting doesn't have the delimiter, then also it works.. thanks to jrook
scala> val s = Seq(1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
s: scala.collection.mutable.Seq[Int] = ArrayBuffer(1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
scala> s.indices.filter( s(_)==0).+:(if(s(0)!=0) -1 else -2).filter(_>= -1 ).reverse.map( {var p=0; x=>{ val y=s.slice(x,s.size-p);p=s.size-x;y}}).reverse
res174: scala.collection.immutable.IndexedSeq[scala.collection.mutable.Seq[Int]] = Vector(ArrayBuffer(1, 2, 1), ArrayBuffer(0, -1), ArrayBuffer(0, 1, 2, 3, 2))
UPDATE1:
More compact version by removing the "reverse" in above
scala> val s = Seq(0,1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
s: scala.collection.mutable.Seq[Int] = ArrayBuffer(0, 1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
scala> s.indices.filter( s(_)==0).+:(if(s(0)!=0) -1 else -2).filter(_>= -1 ).:+(s.size).sliding(2,1).map( x=>s.slice(x(0),x(1)) ).toList
res189: List[scala.collection.mutable.Seq[Int]] = List(ArrayBuffer(0, 1, 2, 1), ArrayBuffer(0, -1), ArrayBuffer(0, 1, 2, 3, 2))
scala> val s = Seq(1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
s: scala.collection.mutable.Seq[Int] = ArrayBuffer(1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
scala> s.indices.filter( s(_)==0).+:(if(s(0)!=0) -1 else -2).filter(_>= -1 ).:+(s.size).sliding(2,1).map( x=>s.slice(x(0),x(1)) ).toList
res190: List[scala.collection.mutable.Seq[Int]] = List(ArrayBuffer(1, 2, 1), ArrayBuffer(0, -1), ArrayBuffer(0, 1, 2, 3, 2))
scala>
Here is a solution I believe is both short and should run in O(n):
def seqSplitter[T](s: ArrayBuffer[T], delimiter : T) =
(0 +: s.indices.filter(s(_)==delimiter) :+ s.size) //find split locations
.sliding(2)
.map(idx => s.slice(idx.head, idx.last)) //extract the slice
.dropWhile(_.isEmpty) //take care of the first element
.toList
The idea is to take all the indices where the delimiter occurs, slide over them and slice the sequence at those locations. dropWhile takes care of the first element being a delimiter or not.
Here I am putting all the data in an ArrayBuffer to ensure slicing will take O(size_of_slice).
val mySeq = ArrayBuffer(0, 1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
seqSplitter(mySeq, 0).toList
Gives:
List(ArrayBuffer(0, 1, 2, 1), ArrayBuffer(0, -1), ArrayBuffer(0, 1, 2, 3, 2))
A more detailed complexity analysis
The operations are:
Filter the delimiter indices (O(n))
loop over a list of indices obtained from previous step (O(num_of_delimeters)); for each pair of indices corresponding to a slice:
Copy the slice from the array and put it into the final collection (O(size_of_slice))
The last two steps sum up to O(n).
I have a user data from movielense ml-100K dataset.
Sample rows are -
1|24|M|technician|85711
2|53|F|other|94043
3|23|M|writer|32067
4|24|M|technician|43537
5|33|F|other|15213
I have read data as RDD as follows-
scala> val user_data = sc.textFile("/home/user/Documents/movielense/ml-100k/u.user").map(x=>x.split('|'))
user_data: org.apache.spark.rdd.RDD[Array[String]] = MapPartitionsRDD[5] at map at <console>:29
scala> user_data.take(5)
res0: Array[Array[String]] = Array(Array(1, 24, M, technician, 85711), Array(2, 53, F, other, 94043), Array(3, 23, M, writer, 32067), Array(4, 24, M, technician, 43537), Array(5, 33, F, other, 15213))
# encode distinct profession with zipWithIndex -
scala> val indexed_profession = user_data.map(x=>x(3)).distinct().sortBy[String](x=>x).zipWithIndex()
indexed_profession: org.apache.spark.rdd.RDD[(String, Long)] = ZippedWithIndexRDD[18] at zipWithIndex at <console>:31
scala> indexed_profession.collect()
res1: Array[(String, Long)] = Array((administrator,0), (artist,1), (doctor,2), (educator,3), (engineer,4), (entertainment,5), (executive,6), (healthcare,7), (homemaker,8), (lawyer,9), (librarian,10), (marketing,11), (none,12), (other,13), (programmer,14), (retired,15), (salesman,16), (scientist,17), (student,18), (technician,19), (writer,20))
I want to do one hot encoding for Occupation column.
Expected output is -
userId Age Gender Occupation Zipcodes technician other writer
1 24 M technician 85711 1 0 0
2 53 F other 94043 0 1 0
3 23 M writer 32067 0 0 1
4 24 M technician 43537 1 0 0
5 33 F other 15213 0 1 0
How do I achieve this on RDD in scala.
I want to perform operation on RDD without converting it to dataframe.
Any help
Thanks
I did this in following way -
1) Read user data -
scala> val user_data = sc.textFile("/home/user/Documents/movielense/ml-100k/u.user").map(x=>x.split('|'))
2) show 5 rows of data-
scala> user_data.take(5)
res0: Array[Array[String]] = Array(Array(1, 24, M, technician, 85711), Array(2, 53, F, other, 94043), Array(3, 23, M, writer, 32067), Array(4, 24, M, technician, 43537), Array(5, 33, F, other, 15213))
3) Create map of profession by indexing-
scala> val indexed_profession = user_data.map(x=>x(3)).distinct().sortBy[String](x=>x).zipWithIndex().collectAsMap()
scala> indexed_profession
res35: scala.collection.Map[String,Long] = Map(scientist -> 17, writer -> 20, doctor -> 2, healthcare -> 7, administrator -> 0, educator -> 3, homemaker -> 8, none -> 12, artist -> 1, salesman -> 16, executive -> 6, programmer -> 14, engineer -> 4, librarian -> 10, technician -> 19, retired -> 15, entertainment -> 5, marketing -> 11, student -> 18, lawyer -> 9, other -> 13)
4) create encode function which does one hot encoding of profession
scala> def encode(x: String) =
|{
| var encodeArray = Array.fill(21)(0)
| encodeArray(indexed_user.get(x).get.toInt)=1
| encodeArray
}
5) Apply encode function to user data -
scala> val encode_user_data = user_data.map{ x => (x(0),x(1),x(2),x(3),x(4),encode(x(3)))}
6) show encoded data -
scala> encode_user_data.take(6)
res71: Array[(String, String, String, String, String, Array[Int])] =
1,24,M,technician,85711,Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0)),
2,53,F,other,94043,Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0)),
3,23,M,writer,32067,Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)),
4,24,M,technician,43537,Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0)),
5,33,F,other,15213,Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0)),
6,42,M,executive,98101,Array(0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)))
[My solution is for Dataframe] This below should help in converting a categorical map to one-hot. You have to create a map catMap object with keys as column name and values as list of categories.
var OutputDf = df
for (cat <- catMap.keys) {
val categories = catMap(cat)
for (oneHotVal <- categories) {
OutputDf = OutputDf.withColumn(oneHotVal,
when(lower(OutputDf(cat)) === oneHotVal, 1).otherwise(0))
}
}
OutputDf
If I have this list:
val aList = List(1,1,1,3,4),List(3,3,5,6,7),List(7,7,7,6,7),List(2,3,3,2,6)
How do I update the list by eliminating non-duplicated numbers on the first head of the List? so the result should be:
val aRes = List(1,1,1), List(3,3), List(7,7,7)
List(2,3,3,2,6) should be removed also since we don't have 3 at the head of the list. My expectation for the result was:
val aRes = aList(1) map {case List(i) => List(aList.groupBy(_(1))}
But it seems not valid for this logic.
beside that, I also need to translate those result values to another list member:
val aScore = List(
/*score for 1*/ List(0, 0, 1500, 2500, 5000),
/*score for 2*/ List(0, 0, 500, 1000, 2000),
/*score for 3*/ List(0, 50, 100, 200, 500),
/*score for 4*/ List(0, 10, 50, 100, 150),
/*score for 5*/ List(0, 10, 50, 100, 150),
/*score for 6*/ List(0, 10, 50, 100, 150),
/*score for 7*/ List(0, 10, 50, 100, 150)
)
val score = ???
so from above aList result, the score must be 1500+50+50 = 1600 as result from 1*3=>1500, 3*2=>50 and 7*3=>50
You want to return something if there are duplicates, and nothing if not, so make a function that returns an Option:
def f(xs: List[Int]) = xs match {
case x0 :: x1 :: _ if x0 == x1 => Some(xs.takeWhile(_ == x0))
case _ => None
}
Then flatMap your list to that to get rid of the optiony bits:
aList.flatMap(f)
For the second part:
def getScore(xs: List[Int]) = aScore(xs.head - 1)(xs.size - 1)
So just map and sum the elements. In total:
aList.flatMap(f).map(getScore).sum
// result = 1600
object parseData {
val inputList = List(List(1,1,1,3,4),List(3,3,5,6,7),List(7,7,7,6,7),List(2,3,3,2,6))
val aScore = List(
/*score for 1*/ List(0, 0, 1500, 2500, 5000),
/*score for 2*/ List(0, 0, 500, 1000, 2000),
/*score for 3*/ List(0, 50, 100, 200, 500),
/*score for 4*/ List(0, 10, 50, 100, 150),
/*score for 5*/ List(0, 10, 50, 100, 150),
/*score for 6*/ List(0, 10, 50, 100, 150),
/*score for 7*/ List(0, 10, 50, 100, 150)
)
def isDuplicated(aList: List[Int]): Boolean = aList.head == aList.tail.head
def getRidOfNonDuplicates(aList: List[Int]): List[Int] = {
val opList = ListBuffer(aList.head)
def loop(aList: List[Int], opList: ListBuffer[Int]): Unit = {
if (aList.tail == Nil) return
if (aList.head == aList.tail.head) opList += aList.tail.head
loop(aList.tail, opList)
}
loop(aList, opList)
opList.toList
}
def printaScoreValue(aList: List[Int]): Unit = println(aScore(aList.head - 1)(aList.length - 1))
val outputList = inputList.filter(isDuplicated(_))
val opList = ListBuffer.empty[List[Int]]
for (aList <- outputList)
opList += getRidOfNonDuplicates(aList)
opList.foreach(printaScoreValue(_))
}
gives
1500
50
50
My first stab was:
scala> val ls = List(List(1,1,1,3,4),List(3,3,5,6,7),List(7,7,7,6,7),List(2,3,3,2,6))
ls: List[List[Int]] = List(List(1, 1, 1, 3, 4), List(3, 3, 5, 6, 7), List(7, 7, 7, 6, 7), List(2, 3, 3, 2, 6))
scala> ls map {
_ groupBy identity filter { case (i, is) => is.length > 1 } flatMap { _._2 }
}
res2: List[List[Int]] = List(List(1, 1, 1), List(3, 3), List(7, 7, 7, 7), List(2, 2, 3, 3))
But as you can see, it not quite what you want. I think the next one nails it:
scala> ls map { l =>
val (h,t) = (l.head, l.tail)
h :: t.takeWhile( _ == h )
} filter { _.length > 1 }
res7: List[List[Int]] = List(List(1, 1, 1), List(3, 3), List(7, 7, 7))
But notice, it is not going to work if List.empty is an element of the outer list.
I want to iterate over a scala list in an incremental way, i.e. the first pass should yield the head, the second the first 2 elements, the next the first 3, etc...
I can code this myself as a recursive function, but does a pre-existing function exist for this in the standard library?
You can use the .inits method to get there, albeit there may be performance issues for a large list (I haven't played around with making this lazy):
scala> val data = List(0,1,2,3,4)
data: List[Int] = List(0, 1, 2, 3, 4)
scala> data.inits.toList.reverse.flatten
res2: List[Int] = List(0, 0, 1, 0, 1, 2, 0, 1, 2, 3, 0, 1, 2, 3, 4)
You can use the take like so:
scala> val myList = 1 to 10 toList
myList: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> for(cnt <- myList.indices) yield myList.take(cnt+1)
res1: scala.collection.immutable.IndexedSeq[List[Int]] = Vector(List(1), List(1, 2), List(1, 2, 3), List(1, 2, 3, 4), List(1, 2, 3, 4, 5), List(1, 2, 3, 4, 5, 6), List(1, 2, 3, 4, 5, 6, 7), List(1, 2, 3, 4, 5, 6, 7, 8), List(1, 2, 3, 4, 5, 6, 7, 8, 9), List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
OK, since I've whined enough, here's an iterator version that tries reasonably hard to not waste space or compute more than is needed at at one point:
class stini[A](xs: List[A]) extends Iterator[List[A]] {
var ys: List[A] = Nil
var remaining = xs
def hasNext = remaining.nonEmpty
def next = {
val e = remaining.head
remaining = remaining.tail
ys = e :: ys
ys.reverse
}
}
val it = new stini(List(1, 2, 3, 4))
it.toList
//> List[List[Int]] =
// List(List(1), List(1, 2), List(1, 2, 3), List(1, 2, 3, 4))
Try: for((x, i) <- l.view.zipWithIndex) println(l.take(i + 1))
if you need something side-effected (I just did println to give you an example)