List whose elements depend on the previous ones - scala

Suppose I have a list of increasing integers. If the difference of 2 consecutive numbers is less than a threshold, then we index them by the same number, starting from 0. Otherwise, we increase the index by 1.
For example: for the list (1,2,5,7,8,11,15,16,20) and the threshold = 3, the output will be: (0, 0, 1, 1, 1, 2, 3, 3, 4).
Here is my code:
val listToGroup = List(1,2,5,7,8,11,15,16,20)
val diff_list = listToGroup.sliding(2,1).map{case List(i, j) => j-i}.toList
val thres = 2
var j=0
val output_ = for(i <- diff_list.indices) yield {
if (diff_list(i) > thres ) {
j += 1
}
j
}
val output = List.concat(List(0), output_)
I'm new to Scala and I feel the list is not used efficiently. How can this code be improved?

You can avoid the mutable variable by using scanLeft to get a more idiomatic code:
val output = diff_list.scanLeft(0) { (count, i) =>
if (i > thres) count + 1
else count
}
Your code shows some constructs which are usually avoided in Scala, but common when coming from procedural langugues, like: for(i <- diff_list.indices) ... diff_list(i) can be replaced with for(i <- diff_list).
Other than that, I think your code is efficient - you need to traverse the list anyway and you do it in O(N). I would not worry about efficiency here, more about style and readability.
My rewrite to how I think it would be more natural in Scala for the whole code would be:
val listToGroup = List(1,2,5,7,8,11,15,16,20)
val thres = 2
val output = listToGroup.zip(listToGroup.drop(1)).scanLeft(0) { case (count, (i, j)) =>
if (j - i > thres) count + 1
else count
}
My adjustments to your code:
I use scanLeft to perform the result collection construction
I prefer x.zip(x.drop(1)) over x.sliding(2, 1) (constructing tuples seems a bit more efficient than constructing collections). You could also use x.zip(x.tail), but that does not handle empty x
I avoid the temporary result diff_list

val listToGroup = List(1, 2, 5, 7, 8, 11, 15, 16, 20)
val thres = 2
listToGroup
.sliding(2)
.scanLeft(0)((a, b) => { if (b.tail.head - b.head > thres) a + 1 else a })
.toList
.tail
You don't need to use mutable variable, you can achieve the same with scanLeft.

Related

Move zeros to the end of an Array

Im trying to solve below problem in scala
Input:[1,0,44,55,0,43,78,99]
output:[1,44,55,43,78,99,0,0]
here is what i have tried
def moveZeros(nums:Array[Int]): Array[Int] ={
for(i<-0 until nums.length ; j<-0 until nums.length){
if(nums(j)!=0)
{
var temp:Int = nums(i)
nums(i)=nums(j)
nums(j)=temp
}
}
nums
}
output :[0,0,1,44,55,78,99,43]
not expected output
Im looking for o(n) time complexity and O(1) space complexity solution
This is a leetcode problem
https://leetcode.com/problems/move-zeroes/
You can try something like that:
nums.zipWithIndex
.sortBy(t => if (t._1 == 0) Int.MaxValue else t._2)
.map(_._1)
zipWithIndex will map your collection into sequence of tuples of element value and it's index (i.e. [(1, 0), (0, 21), (44, 2)] for start of your example array)
sortBy will perform the ordering by either index of element or Int.MaxValue
map will return map to the original element.
i have rewritten my code with while loop it seems to work, lemme know if there is more elegant solution which satisfies linear time complexity and constant space complexity
def moveZeros(nums: Array[Int]): Array[Int] = {
var i = 0
var j = 0
while ( {
i < nums.length && j < nums.length
}) {
if (nums(j) != 0) {
val tmp = nums(i)
nums(i)=nums(j)
nums(j) = tmp
i+=1
}
j += 1
}
nums
}
This is a pure FP solution with O(n) time complexity and O(1) space complexity.
Unlike any of the other solutions so far, it can work for very large input that doesn't fit in memory:
object MoveZeros extends App {
def moveZerosToEnd(input: Iterator[Int]): Iterator[Int] = {
val endOfInputSignal = None
val iteratorWithEndSignal: Iterator[Option[Int]] =
input.map(Some(_)) ++ Iterator.single(endOfInputSignal)
iteratorWithEndSignal.scanLeft((0, Iterator.empty[Int])) {
case ((zerosCounter, _), value) => value match {
case Some(value) =>
if (value == 0)
// Count zero and drop it
(zerosCounter + 1, Iterator.empty)
else
(zerosCounter, Iterator.single(value))
case None =>
// Add counted zeros to the end
(zerosCounter, Iterator.fill(zerosCounter)(0))
}
}.flatMap(_._2)
}
val input = List(1,0,44,55,0,43,78,99)
val expected = List(1,44,55,43,78,99,0,0)
val res = moveZerosToEnd(input.iterator)
.toList // To list only for easy testing
assert(res == expected)
println(res)
}
Functional and immutable solution, also very simple to understand:
def moveZerosToEnd(input: Seq[Int]): Seq[Int] = {
val ZERO = 0
val zeroCount = input.count(_==ZERO)
val removeZeros = input.filter(_!=ZERO)
val zeroSuffix = Seq.fill(zeroCount)(ZERO)
removeZeros ++ zeroSuffix
}
Time complexity: O(n): Fixed number of iterations over the sequence.
Space complexity: O(n): removeZeros, zeroSuffix and the output line may consume up to n space, so complexity is O(n).
You can find all the immutable, functional, "true Scala" way of doing it in the above answers. But, considering the O(N) time-complexity and O(1) space complexity nothing beats a mutable, efficient, in-place algorithm!
Here is the implementation with Scala's array using foldLeft:
val arr = Array(1, 0, 44, 55, 0, 43, 78, 99)
val lastNonZero = arr.foldLeft(0) {
(zeros, elem) => if (elem != 0) { arr(zeros) = elem; zeros+1 } else zeros
}
(lastNonZero until arr.length).foreach{ i => arr(i) = 0 }
No extra space due to collection creation (not even .toList/.toArray) and no sorting.

How to print a value outside a for loop in scala?

I am new to scala and would like to know way to access val which is defined inside for loop and would like to write that val to a file outside for loop.
def time[A](logFile: String, description: String)(job: => A): Unit = {
var totalDuration: Long = 0
for (i <- 1 to 3) {
val currentTime = System.currentTimeMillis
val result = job
val finalTime = System.currentTimeMillis
val duration = finalTime - currentTime
totalDuration = if (totalDuration == 0) duration else totalDuration.min(duration)
}
val pw = new PrintWriter(new FileOutputStream(new File(logFile),true))
pw.write(description + " " + result + " " + totalDuration +" ms"+"\n")
pw.flush()
pw.close
}
In the above code i am calculating my result which contains the length of bytes read from other function and would like to calculate the time it takes to read the total bytes. I would like to iterate 3 times and take the minimum of all the three. The val result contains the bytes length which also needs to be written in a file. i get a error because i am accessing the result val outside the scope of for loop. Can someone please help me solve this error. How can i access the val result outside for loop to write it to a file ?
Thanks in advance!!
While your question is answered, the for loop is not in it's typical form, which would look more like this:
def time[A] (logFile: String, description: String) (job: => A): Unit = {
val (result, totalDuration): (A, Long) = (for { i <- 1 to 3
currentTime = System.currentTimeMillis
result = job
finalTime = System.currentTimeMillis
duration = finalTime - currentTime
} yield (result, duration)).minBy {case (r, d) => d}
val pw = new PrintWriter (new FileOutputStream (new File (logFile), true))
pw.write (description + " " + result + " " + totalDuration +" ms"+"\n")
pw.flush()
pw.close
}
If I understood your code correctly. I don't know whether a side effect yields to different results for each job invocation.
I missed the internal discussion of the for-loop invention/definition, why the keyword val should be omitted here, but it is quiet handy.
What is more important, is, that you usually have all temporary assignments in the for (...(here part)...) { not here}. The consequences of round or curly braces in the first part aren't totally clear to me, but if you use round parens, you have terminate most statements with a semicolon.
scala> for (i <- 1 to 3;
| j <- 4 to 5;
| k = j-i;
| l = k/2) yield l * l;
res2: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 4, 1, 1, 0, 1)
Note that neither i, nor j, k, l where declared as val or var.
scala> for {i <- 1 to 3
| j <- 4 to 5
| k = j-i
| l = k/2} yield l * l;
res3: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 4, 1, 1, 0, 1)
You will find multiple questions here, which explain, how a for-loop is and can be translatet to a flatMap/map-combination, eventually with filter:
scala> for {i <- 1 to 3
| j <- 4 to 5
| k = j-i
| if (k > 1)
| l = k/2 } yield l * l;
res5: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 4, 1, 1, 1)
And instead of yielding just one value, you can yield a tuple, and assign by
val (a:X, b:Y) = (for ..... yield (aa, bb))
The
yield (result, duration)).minBy {case (r, d) => d}
takes a tuple (result, duration) and selects the minimum by duration, but yields both values.
you can use yield. Yield will return data from for loop after completion of loop and use that data accordingly. Since I do not have your code. see this example
val j = for (i <- 1 to 10) yield i
println(j)
output of j will be
Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
For replacing your for loop to calculate the total duration of some jobs that are executed sequentially, you could use foldLeft
Make use of yield or you can use any of the fold method. Or if you are good with recursion you can use a tailrec method which returns what is Desired. Yield is the most simplest way to do it.
val answer = for(i<- 1 to 10) yield i
println(answer) // Vector(1,2,3,4,5,6,7,8,9,10)

Best way to handle while loop style program in Scala

I have a simple program written in C++. It generates random numbers, and stop when the sum of those numbers equal or greater than 100. The code looks like:
vector<int> container;
while(container.sum() <100)
{
int new_number = rand()%10 + 1 ;// generate a number in range 1 to 10
container.push_back(new_number); // add new number to the container
}
What is the best way to handle the task in Scala? (without using while loop?)
It seems that FoldLeft or FoldRight function doesn't have ability to break at a condition?
Create an infinite Stream of random numbers (requires very little CPU and memory), take only what you need, then turn the result Stream into the desired collection type.
val randoms = Stream.continually(util.Random.nextInt(10)+1)
val container = randoms.take(randoms.scan(0)(_+_).indexWhere(_>=100)).toVector
Added bonus is that the sums are calculated as you go, i.e. added to the previous sum, not summing from the beginning each time.
Here's one approach to handle a while loop using a tail-recursive function as follows:
#scala.annotation.tailrec
def addToContainer(container: Vector[Int], max: Int): Vector[Int] = {
val newContainer = container ++ Vector(scala.util.Random.nextInt(10) + 1)
if (newContainer.sum >= max) container
else addToContainer(newContainer, max)
}
addToContainer(Vector[Int](), 100)
// res1: Vector[Int] = Vector(9, 9, 5, 9, 3, 5, 2, 5, 10, 7, 6, 4, 5, 5, 9, 3)
res1.sum
// res2: Int = 96
Here's one way to do it:
val randomNumberGenerator = new scala.util.Random
def sumUntil(list: List[Int]): List[Int] = list match {
case exceeds if list.filter(_ > 0).sum > 100 => list
case _ => sumUntil(list :+ (randomNumberGenerator.nextInt(10) + 1))
}
To explain the solution:
Create an instance of scala.util.Random which will help us generate random numbers
sumUntil will pattern match; if the sum of the list exceeds 100, return it.
In the event that the sum does not exceed 100, call sumUntil again, but with another random number generated between 10 and 1 (inclusive). Keep in mind that the _ means, "I don't care about the value, or even the type." _ is anything else but the case where the sum of all the integers in our list is greater than 100.
If you're new to Scala, I understand that it may be a bit rough on the eyes to read. Below is a refined version:
val randomNumberGenerator = new scala.util.Random
def sumUntil(list: List[Int]): List[Int] = list match {
case exceeds if sumList(list) > 100 => list
case _ => sumUntil(appendRandomNumberToList(list))
}
private def sumList(list: List[Int]): Int = {
list.filter(_ > 0).sum
}
private def appendRandomNumberToList(list: List[Int]): List[Int] = {
list :+ randomNumberGenerator.nextInt(10) + 1
}
If your loop just scans through the collection, use fold or reduce.
If it needs some custom terminate condition, recursion is favored.

How to capture inner matched value in indexWhere vector expression?

Using a Vector[Vector[Int]] reference v, and the expression to find a given number num:
val posX = v.indexWhere(_.indexOf(num) > -1)
Is there any way to capture the value of _.indexOf(num) to use after the expression (i.e. the posY value)? The following signals an error 'Illegal start of simple expression':
val posX = v.indexWhere((val posY = _.indexOf(num)) > -1)
If we do not mind using a variable then we can capture indexOf() value of inner Vector (_ in the below code) in a var and use it later to build the y position:
val posX = v.indexWhere(_.indexOf(num) > -1)
val posY = v(posX).indexOf(num)
There are lots of nice functional ways to do this. The following is probably one of the more concise:
val v = Vector(Vector(1, 2, 3), Vector(4, 5, 6), Vector(7, 8, 9))
val num = 4
val Some((posY, posX)) = v.map(_ indexOf num).zipWithIndex.find(_._1 > -1)
// posY: Int = 0
// posX: Int = 1
Note that there's a lot of extra work going on here, though—we're creating a couple of intermediate collections, parts of which we don't need, etc. If you're calling this thing a lot or on very large collections, you unfortunately may need to take a more imperative approach. In that case I'd suggest bundling up all the unpleasantness:
def locationOf(v: Vector[Vector[Int]])(num: Int): Option[(Int, Int)] = {
var i, j = 0
var found = false
while (i < v.size && !found) {
j = 0
while (j < v(i).size && !found)
if (v(i)(j) == num) found = true else j += 1
if (!found) i += 1
}
if (!found) None else Some(i, j)
}
Not as elegant, but this method is probably going to be a lot faster and more memory efficient. It's small enough that it isn't likely to contain any of the bugs that this kind of programming is so prone to, and it's referentially transparent—all the mutation is local.
From my armchair,
scala> val v = Vector(Vector(1, 2, 3), Vector(4, 5, 6), Vector(7, 8, 9))
scala> v.zipWithIndex collectFirst {
| case (e, i) if (e indexOf num) >= 0 =>
| (i, e indexOf num)
| }
res7: Option[(Int, Int)] = Some((1,0))
I haven't done the armchair math, but that's one intermediate collection compared to Travis's. But see Travis's comment that the result inner index is computed twice here, and the whole point was not to do that.
Here is a solution that will only evaluate up until it finds the required element. I personally find it more readable and you can reuse it across programs. You can obviously make this more general if need be.
val v = Vector(Vector(1, 2, 3), Vector(4, 5, 6))
def findElem(i: Int, vs: Vector[Vector[Int]]): (Int, Int) =
(for {
row <- vs.indices.toStream
col <- vs(row).indices.toStream
if vs(row)(col) == i
} yield (row, col)).head
findElem(5, v) // (1, 1)
You could remove the .toStream methods if you want all positions. Using the .toStream just means that you will only evaluate up until the first occurrence.

help rewriting in functional style

I'm learning Scala as my first functional-ish language. As one of the problems, I was trying to find a functional way of generating the sequence S up to n places. S is defined so that S(1) = 1, and S(x) = the number of times x appears in the sequence. (I can't remember what this is called, but I've seen it in programming books before.)
In practice, the sequence looks like this:
S = 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7 ...
I can generate this sequence pretty easily in Scala using an imperative style like this:
def genSequence(numItems: Int) = {
require(numItems > 0, "numItems must be >= 1")
var list: List[Int] = List(1)
var seq_no = 2
var no = 2
var no_nos = 0
var num_made = 1
while(num_made < numItems) {
if(no_nos < seq_no) {
list = list :+ no
no_nos += 1
num_made += 1
} else if(no % 2 == 0) {
no += 1
no_nos = 0
} else {
no += 1
seq_no += 1
no_nos = 0
}
}
list
}
But I don't really have any idea how to write this without using vars and the while loop.
Thanks!
Pavel's answer has come closest so far, but it's also inefficient. Two flatMaps and a zipWithIndex are overkill here :)
My understanding of the required output:
The results contain all the positive integers (starting from 1) at least once
each number n appears in the output (n/2) + 1 times
As Pavel has rightly noted, the solution is to start with a Stream then use flatMap:
Stream from 1
This generates a Stream, a potentially never-ending sequence that only produces values on demand. In this case, it's generating 1, 2, 3, 4... all the way up to Infinity (in theory) or Integer.MAX_VALUE (in practice)
Streams can be mapped over, as with any other collection. For example: (Stream from 1) map { 2 * _ } generates a Stream of even numbers.
You can also use flatMap on Streams, allowing you to map each input element to zero or more output elements; this is key to solving your problem:
val strm = (Stream from 1) flatMap { n => Stream.fill(n/2 + 1)(n) }
So... How does this work? For the element 3, the lambda { n => Stream.fill(n/2 + 1)(n) } will produce the output stream 3,3. For the first 5 integers you'll get:
1 -> 1
2 -> 2, 2
3 -> 3, 3
4 -> 4, 4, 4
5 -> 5, 5, 5
etc.
and because we're using flatMap, these will be concatenated, yielding:
1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, ...
Streams are memoised, so once a given value has been calculated it'll be saved for future reference. However, all the preceeding values have to be calculated at least once. If you want the full sequence then this won't cause any problems, but it does mean that generating S(10796) from a cold start is going to be slow! (a problem shared with your imperative algorithm). If you need to do this, then none of the solutions so far is likely to be appropriate for you.
The following code produces exactly the same sequence as yours:
val seq = Stream.from(1)
.flatMap(Stream.fill(2)(_))
.zipWithIndex
.flatMap(p => Stream.fill(p._1)(p._2))
.tail
However, if you want to produce the Golomb sequence (that complies with the definition, but differs from your sample code result), you may use the following:
val seq = 1 #:: a(2)
def a(n: Int): Stream[Int] = (1 + seq(n - seq(seq(n - 2) - 1) - 1)) #:: a(n + 1)
You may check my article for more examples of how to deal with number sequences in functional style.
Here is a translation of your code to a more functional style:
def genSequence(numItems: Int): List[Int] = {
genSequenceR(numItems, 2, 2, 0, 1, List[Int](1))
}
def genSequenceR(numItems: Int, seq_no: Int, no:Int, no_nos: Int, numMade: Int, list: List[Int]): List[Int] = {
if(numMade < numItems){
if(no_nos < seq_no){
genSequenceR(numItems, seq_no, no, no_nos + 1, numMade + 1, list :+ no)
}else if(no % 2 == 0){
genSequenceR(numItems, seq_no, no + 1, 0, numMade, list)
}else{
genSequenceR(numItems, seq_no + 1, no + 1, 0, numMade, list)
}
}else{
list
}
}
The genSequenceR is the recursive function that accumulates values in the list and calls the function with new values based on the conditions. Like the while loop, it terminates, when numMade is less than numItems and returns the list to genSequence.
This is a fairly rudimentary functional translation of your code. It can be improved and there are better approaches typically used. I'd recommend trying to improve it with pattern matching and then work towards the other solutions that use Stream here.
Here's an attempt from a Scala tyro. Keep in mind I don't really understand Scala, I don't really understand the question, and I don't really understand your algorithm.
def genX_Ys[A](howMany : Int, ofWhat : A) : List[A] = howMany match {
case 1 => List(ofWhat)
case _ => ofWhat :: genX_Ys(howMany - 1, ofWhat)
}
def makeAtLeast(startingWith : List[Int], nextUp : Int, howMany : Int, minimumLength : Int) : List[Int] = {
if (startingWith.size >= minimumLength)
startingWith
else
makeAtLeast(startingWith ++ genX_Ys( howMany, nextUp),
nextUp +1, howMany + (if (nextUp % 2 == 1) 1 else 0), minimumLength)
}
def genSequence(numItems: Int) = makeAtLeast(List(1), 2, 2, numItems).slice(0, numItems)
This seems to work, but re-read the caveats above. In particular, I am sure there is a library function that performs genX_Ys, but I couldn't find it.
EDIT Could be
def genX_Ys[A](howMany : Int, ofWhat : A) : Seq[A] =
(1 to howMany) map { x => ofWhat }
Here is a very direct "translation" of the definition of the Golomb seqence:
val it = Iterator.iterate((1,1,Map(1->1,2->2))){ case (n,i,m) =>
val c = m(n)
if (c == 1) (n+1, i+1, m + (i -> n) - n)
else (n, i+1, m + (i -> n) + (n -> (c-1)))
}.map(_._1)
println(it.take(10).toList)
The tripel (n,i,m) contains the actual number n, the index i and a Map m, which contains how often an n must be repeated. When the counter in the Map for our n reaches 1, we increase n (and can drop n from the map, as it is not longer needed), else we just decrease n's counter in the map and keep n. In every case we add the new pair i -> n into the map, which will be used as counter later (when a subsequent n reaches the value of the current i).
[Edit]
Thinking about it, I realized that I don't need indexes and not even a lookup (because the "counters" are already in the "right" order), which means that I can replace the Map with a Queue:
import collection.immutable.Queue
val it = 1 #:: Iterator.iterate((2, 2, Queue[Int]())){
case (n,1,q) => (n+1, q.head, q.tail + (n+1))
case (n,c,q) => (n,c-1,q + n)
}.map(_._1).toStream
The Iterator works correctly when starting by 2, so I had to add a 1 at the beginning. The second tuple argument is now the counter for the current n (taken from the Queue). The current counter could be kept in the Queue as well, so we have only a pair, but then it's less clear what's going on due to the complicated Queue handling:
val it = 1 #:: Iterator.iterate((2, Queue[Int](2))){
case (n,q) if q.head == 1 => (n+1, q.tail + (n+1))
case (n,q) => (n, ((q.head-1) +: q.tail) + n)
}.map(_._1).toStream