Related
I would like to know if below function can be rewritten using tail recursion and using recursion in this case is any helpful in terms of time/space complexity?, below is what i have tried without tail recursion
input:[4,2,4,6]
output:[48,96,48,32]
def productExceptSelf(nums: Array[Int]): Array[Int]={
val len = nums.length
val output_arr= new Array[Int](len)
output_arr(0)=1
for(i<- 1 to len-1)
{
output_arr(i) = nums(i-1) * output_arr(i-1)
}
var R =1
var j=len-1
while(j>=0)
{
output_arr(j) = output_arr(j)* R
R = R * nums(j)
j-=1
}
output_arr
}
Solution without using division.
def productExceptSelf(nums: Array[Int]): Array[Int] =
Array.fill(nums.length)(nums)
.zipWithIndex
.map{case (ns,x) => ns.patch(x,Seq(),1).product}
Not sure how would you expect to write this using tail-recursion, but the simplest way would be something like this:
PS: I am using ArraySeq which is an immutable array (that was introduced on 2.13), feel free to keep using normal arrays.
def productExceptSelf(nums: ArraySeq[Int]): ArraySeq[Int] = {
val totalProduct = nums.product
nums.map(x => totalProduct / x)
}
Solution without using division.
def productExceptSelf(nums: ArraySew[Int]) : ArraySeq[Int] =
ArraySeq.tabulate(nums.length) { i =>
nums.foldLeft(1 -> 0) { case ((acc, j), x) =>
val newAcc = if (i == j) acc else acc * x
newAcc -> (j + 1)
}._1
}
Try this. It keeps track of the index and multiplies if the index of the current element isn't the same. However, it's not very idiomatic.
def productExceptSelf(nums: Array[Int]): Array[Int] =
productExceptSelf(nums, Array.fill(nums.size)(1), 0).toArray
def productExceptSelf(orig: Array[Int], res: Array[Int], i: Int): Array[Int] =
if (i == orig.size) res
else productExceptSelf(
orig,
res.zipWithIndex.map {
case (n, j) => if (j == i) n else n * orig(i)
},
i + 1
)
I like this one better:
def productExceptSelf(nums: Array[Int]): Array[Int] =
nums.indices.map {
i => nums.slice(0, i).product * nums.slice(i + 1, nums.size).product
}.toArray
You might prefer a view to do it lazily
def productExceptSelf(nums: Array[Int]) =
nums.indices.map {
i => nums.view.slice(0, i).product * nums.view.slice(i + 1, nums.size).product
}
# Starting from the right and recursing left, compute the right side product
# and pass it down. Upon reaching the left, compute the left side product,
# update the array, and bubble that value up.
def prod_not_self(arr, i, right):
if (i == 0):
left = 1
else:
left = arr[i-1] * prod_not_self(arr, i - 1, right * arr[i])
arr[i] = right * left
return left
if (__name__ == '__main__'):
arr = [1, 2, 3, 4]
print(arr)
prod_not_self(arr, len(arr) - 1, 1)
print(arr)
print()
arr = [-1, 1, 0, -3, 3]
print(arr)
prod_not_self(arr, len(arr) - 1, 1)
print(arr)
I can use the following code to sum up squares of every digits. how could it be changed to only do it for even-positioned digits starting from 2nd position ?
var sum:Int = num.toString.map{ _.asDigit }.map(x => x*x).sum
If you want every even-positioned value, one way of doing that is with grouped and head.
To start at the second digit, take the tail of the list before grouping.
val sum = num.toString.map{ _.asDigit }.tail.grouped(2).map(_.head).map(x => x*x).sum
See it working here.
A possible solution to keep only even-positioned is to use zipWithIndex:
// Your initial code
def squareDigitsSummation(n: Int): Int =
n.toString.map{ _.asDigit }.map(x => x*x).sum
def squareEvenPositionedDigitsSummation(n: Int): Int =
n.toString.view.
tail.
map(_.asDigit).
zipWithIndex.
collect { case (n, i) if i % 2 != 0 => n * n }.
sum
assert(squareDigitsSummation(1234) == 30)
assert(squareEvenPositionedDigitsSummation(1234) == 9)
Please note that zipWithIndex is 1-based, so I had to somewhat counter-intuitively negate the filter predicate to keep odd-indexed pairs (I assumed you wanted to have 0-based indexes, given you explicitly mentioned you didn't want the 0th element to be kept).
Sum of squares of even digits from the right - tail recursion
def sumOfEvenDigitsTailRecursion(num: Int): Int = {
#tailrec def impl(num: Int, idx: Int, acc: Int): Int = {
if (num == 0) acc
else if (idx % 2 == 0) impl(num / 10, idx + 1, acc + ((num % 10) * (num % 10)))
else impl(num / 10, idx + 1, acc)
}
impl(num, 1, 0)
}
assert(sumOfEvenDigitsTailRecursion(123456) == 5*5 + 3*3 +1*1)
Sum of squares of even digits from the left - tail recursion
def sumOfEvenDigitsTailRecursion(num: Int): Int = {
#tailrec def impl(num: Int, idx: Int, acc: Int, length: Int = -1): Int = {
if (length % 2 == 0) {
impl(num / 10, idx, acc + ((num % 10) * (num % 10)))
} else {
if (num == 0) acc
else if (idx % 2 == 0) impl(num / 10, idx + 1, acc + ((num % 10) * (num % 10)))
else impl(num / 10, idx + 1, acc)
}
}
impl(num, 1, 0, (Math.log10(num) + 1).toInt)
}
assert(sumOfEvenDigitsTailRecursion(123456) == 2*2 + 4*4 + 6*6)
Sum of squares of even digits from the left - iterators
def sumOfEvenDigitsIterators(num: Int): Int =
num
.toString
.iterator
.map(_.asDigit)
.grouped(2)
.collect{ case ArraySeq(_, b) => b }
.map(x => x * x)
.sum
Benchmark: sbt "jmh:run -i 10 -wi 10 -f 2 -t 1 bench.So59627557"
#State(Scope.Benchmark)
#BenchmarkMode(Array(Mode.Throughput))
class So59627557 {
def _sumOfEvenDigitsIterators(num: Int): Int =
num
.toString
.iterator
.map(_.asDigit)
.grouped(2)
.collect{ case ArraySeq(_, b) => b }
.map(x => x * x)
.sum
def _sumOfEvenDigitsTailRecursion(num: Int): Int = {
#tailrec def impl(num: Int, idx: Int, acc: Int, length: Int = -1): Int = {
if (length % 2 == 0) {
impl(num / 10, idx, acc + ((num % 10) * (num % 10)))
} else {
if (num == 0) acc
else if (idx % 2 == 0) impl(num / 10, idx + 1, acc + ((num % 10) * (num % 10)))
else impl(num / 10, idx + 1, acc)
}
}
impl(num, 1, 0, (Math.log10(num) + 1).toInt)
}
val num: Int = (math.random * 100000000).toInt
#Benchmark def sumOfEvenDigitsIterators: Int = _sumOfEvenDigitsIterators(num)
#Benchmark def sumOfEvenDigitsTailRecursion: Int = _sumOfEvenDigitsTailRecursion(num)
}
results
[info] Benchmark Mode Cnt Score Error Units
[info] So59627557.sumOfEvenDigitsIterators thrpt 20 2033487.342 ± 187156.764 ops/s
[info] So59627557.sumOfEvenDigitsTailRecursion thrpt 20 27431255.610 ± 835429.506 ops/s
Tail-recursive solution seems to have more than 10x throughput than iterators-based solution.
Why not use regex?
val num = 24874
var sum: Int = "\\d{2}".r
.findAllIn(num.toString)
.map(_.last.asDigit)
.map(v => v * v)
.sum
I am wondering if there's a way to deal with a while (n > 0) loop in a more functional way, I have a small Scala app that counts the number of digits equal to K from a range from 1 to N:
for example 30 and 3 would return 4 [3, 13, 23, 30]
object NumKCount {
def main(args: Array[String]): Unit = {
println(countK(30,3))
}
def countKDigit(n:Int, k:Int):Int = {
var num = n
var count = 0
while (num > 10) {
val digit = num % 10
if (digit == k) {count += 1}
num = num / 10
}
if (num == k) {count += 1}
count
}
def countK(n:Int, k:Int):Int = {
1.to(n).foldLeft(0)((acc, x) => acc + countKDigit(x, k))
}
}
I'm looking for a way to define the function countKDigit using a purely functional approach
First expand number n into a sequence of digits
def digits(n: Int): Seq[Int] = {
if (n < 10) Seq(n)
else digits(n / 10) :+ n % 10
}
Then reduce the sequence by counting occurrences of k
def countKDigit(n:Int, k:Int):Int = {
digits(n).count(_ == k)
}
Or you can avoid countKDigit entirely by using flatMap
def countK(n:Int, k:Int):Int = {
1.to(n).flatMap(digits).count(_ == k)
}
Assuming that K is always 1 digit, you can convert n to String and use collect or filter, like below (there's not much functional stuff you can do with Integer):
def countKDigit(n: Int, k: Int): Int = {
n.toString.collect({ case c if c.asDigit == k => true }).size
}
or
def countKDigit(n: Int, k: Int): Int = {
n.toString.filter(c => c.asDigit == 3).length
}
E.g.
scala> 343.toString.collect({ case c if c.asDigit == 3 => true }).size
res18: Int = 2
scala> 343.toString.filter(c => c.asDigit == 3).length
res22: Int = 2
What about the following approach:
scala> val myInt = 346763
myInt: Int = 346763
scala> val target = 3
target: Int = 3
scala> val temp = List.tabulate(math.log10(myInt).toInt + 1)(x => math.pow(10, x).toInt)
temp: List[Int] = List(1, 10, 100, 1000, 10000, 100000)
scala> temp.map(x => myInt / x % 10)
res17: List[Int] = List(3, 6, 7, 6, 4, 3)
scala> temp.count(x => myInt / x % 10 == target)
res18: Int = 2
Counting the occurrences of a single digit in a number sequence.
def countK(n:Int, k:Int):Int = {
assert(k >= 0 && k <= 9)
1.to(n).mkString.count(_ == '0' + k)
}
If you really only want to modify countKDigit() to a more functional design, there's always recursion.
def countKDigit(n:Int, k:Int, acc: Int = 0):Int =
if (n == 0) acc
else countKDigit(n/10, k, if (n%10 == k) acc+1 else acc)
Imagine I have an unsorted list of positive & negative ints. I want to return a list containing all the positive ints, and the first negative number, but then ignore all subsequent negative numbers from the list, while preserving the ordering.
Imperatively I could do:
l = [1, 2, -4, 5, -6, -1, 3]
out = []
first = true
for n in l:
if n >= 0:
out.push(n)
else if first:
out.push(n)
first = false
// out = [1, 2, -4, 5, 3]
How could I do this with FP in Scala? I was thinking (probably won't compile...):
val l = List(1, 2, -4, 5, -6, -1, 3)
val posl = l.map(_ >= 0)
val negl = l.zipWithIndex.map((n, i) => if (n < 0) (i, n) else (None, None)).head
// now split posl at negl._1, and create a new list of leftSlice :: negl._2 :: rightSlice?
Is this the right approach, or is there a more elegant, succinct way?
It wouldn't be a proper functional programming question without a slightly-too-clever recursion+pattern matching answer.
def firstNegAllPos(l:List[Int]):List[Int] = {
l match{
case x::xs if x>=0 => x::firstNegAllPos(xs)
case x::xs if x<0 => x::xs.filter(_>=0)
case Nil => Nil
}
}
Here is a tail-recursive way. Compared to m-z's answer, it iterates your list only one time, compared to Dimas answer, it does not use mutable state, so it is pure functional.
def firstNegAllPos(list: List[Int]) : List[Int] = {
def loop(in: List[Int], out: List[Int], negfound: Boolean) : List [Int] = {
in match {
case Nil => out
case head :: tail =>
if (negfound)
loop(tail, if (head < 0) out else head :: out, true)
else
loop(tail, head :: out, head < 0)
}
}
loop(list, Nil, false)
}
firstNegAllPos(List(1, 2, -4, 5, -6, -1, 3)) // List(3, 5, -4, 2, 1)
Edit:
The above implementation provides a reversed result. In order to preserve order you can do following:
def firstNegAllPos(list: List[Int]) : List[Int] = {
def loop(in: List[Int], out: List[Int], negfound: Boolean) : List [Int] = {
in match {
case Nil => out
case head :: tail =>
if (negfound)
loop(tail, if (head < 0) out else head :: out, true)
else
loop(tail, head :: out, head < 0)
}
}
loop(list, Nil, false).reverse
}
firstNegAllPos(List(1, 2, -4, 5, -6, -1, 3)) // List(1, 2, -4, 5, 3)
You can do it in one pass provided you don't mind keeping a bit of state around - mind the var neg:
var neg = false
list.filter {
case x if x > 0 => true
case _ if !neg => neg = true
}
A direct translation of the requirement is pretty clear, takes one pass over the list, and is functional:
val l = List(1, 2, -4, 5, -6, -1, 3)
// split into any initial positive numbers, and the rest of the list
val (pos, firstneg) = l.span(_ >= 0)
// if there were no negative numbers, return the original list.
// otherwise, it's the initial positives, the first negative, and
// the positive numbers from the rest of the list.
if (firstNeg.isEmpty) l else pos:::List(firstneg.head):::firstneg.tail.filter(_>=0)
//> res0: List[Int] = List(1, 2, -4, 5, 3)
(The List around firstneg.head is just for the symmetry of ::: both sides)
val l = List(1, 2, -4, 5, -6, -1, 3)
val (left, right) = l.span(_ > 0)
val result = right.headOption match {
case Some(n) => (left :+ n) ++ right.tail.filter(_ > 0)
case None => left
}
This is an obvious work for fold operation!
val l = List(1, 2, -4, 5, -6, -1, 3)
var result = l.foldLeft((true, Vector.empty[Int])) {
case ((f, r), x) if x >= 0 => (f, r :+ x)
case ((f, r), x) if f => (false, r :+ x)
case ((f, r), x) => (f, r)
}._2
println(result) // Vector(1, 2, -4, 5, 3)
I used a vector as an intermediate structure; you can convert it to a list with toList, if you need it. Or you can use it instead of the Vector, but you will have to reverse the addition order (r :+ x => x :: r) and then reverse the list in the end with reverse method.
If you want to maintain the order (i.e., the position of the negative), you could do something like this:
val list = List(1, 2, -4, 5, -6, -1, 3)
val negIndex = list.indexWhere(_ < 0)
val positive = list.zipWithIndex.filter { case (num, index) =>
num >= 0 || index == negIndex
}.map(_._1)
The negative requirement makes it hard to keep it more succinct than that. My strategy is to just grab the index of the first negative with indexWhere (will be -1 if there is none), then filter all the negatives out of the list, except for the index of the first negative. If the index was -1, no harm, no foul.
Here is tail recursive solution preserving order:
def posNeg(xs: List[Int]): List[Int] = {
#tailrec
def go(tail: List[Int], res: List[Int]): List[Int] = {
tail match {
case h :: t =>
if (h >= 0) go(t, h :: res)
else (h :: res).reverse ::: t.filter(_ > 0)
case _ => res
}
}
go(xs, Nil)
}
There are a lot of tail-recursive solutions, but they're all longer than they need to be.
def oneNeg(xs: List[Int]): List[Int] = {
def loop(in: List[Int], out: List[Int], neg: Int): List[Int] = in match {
case Nil => out
case x :: rest =>
if (neg < 0 && x < 0) loop(rest, out, neg)
else loop(rest, x :: out, x min neg)
}
loop(xs, Nil, 0).reverse
}
If this is not a public-facing API, you can make it shorter yet by just exposing the inner method alone:
def oneNeg(in: List[Int], out: List[Int] = Nil, neg: Int = 0): List[Int] =
in match {
case Nil => out.reverse
case x :: rest =>
if (neg < 0 && x < 0) oneNeg(rest, out, neg)
else oneNeg(rest, x :: out, x min neg)
}
Here is an improvement on the most concise answer I saw, by #sschaef in a comment:
val l = List(1, 2, -4, 5, -6, -1, 3)
l.span(_>=0) match { case (left, Nil) => left
case (left, x::right) => left ++ (x +: right.filter(_>=0)) }
You can try:
val list = List(1, 2, -4, 5, -6, -1, 3)
val index = list.indexWhere(_ < 0) + 1
list.take(index) ++ list.drop(index).filter(_ > 0)
Lets assume we have a Scala list:
val l1 = List(1, 2, 3, 1, 1, 3, 2, 5, 1)
We can easily remove duplicates using the following code:
l1.distinct
or
l1.toSet.toList
But what if we want to remove duplicates only if there are more than 2 of them? So if there are more than 2 elements with the same value we remain only two and remove the rest of them.
I could achieve it with following code:
l1.groupBy(identity).mapValues(_.take(2)).values.toList.flatten
that gave me the result:
List(2, 2, 5, 1, 1, 3, 3)
Elements are removed but the order of remaining elements is different from how these elements appeared in the initial list. How to do this operation and remain the order from original list?
So the result for l1 should be:
List(1, 2, 3, 1, 3, 2, 5)
Not the most efficient.
scala> val l1 = List(1, 2, 3, 1, 1, 3, 2, 5, 1)
l1: List[Int] = List(1, 2, 3, 1, 1, 3, 2, 5, 1)
scala> l1.zipWithIndex.groupBy( _._1 ).map(_._2.take(2)).flatten.toList.sortBy(_._2).unzip._1
res10: List[Int] = List(1, 2, 3, 1, 3, 2, 5)
My humble answer:
def distinctOrder[A](x:List[A]):List[A] = {
#scala.annotation.tailrec
def distinctOrderRec(list: List[A], covered: List[A]): List[A] = {
(list, covered) match {
case (Nil, _) => covered.reverse
case (lst, c) if c.count(_ == lst.head) >= 2 => distinctOrderRec(list.tail, covered)
case _ => distinctOrderRec(list.tail, list.head :: covered)
}
}
distinctOrderRec(x, Nil)
}
With the results:
scala> val l1 = List(1, 2, 3, 1, 1, 3, 2, 5, 1)
l1: List[Int] = List(1, 2, 3, 1, 1, 3, 2, 5, 1)
scala> distinctOrder(l1)
res1: List[Int] = List(1, 2, 3, 1, 3, 2, 5)
On Edit: Right before I went to bed I came up with this!
l1.foldLeft(List[Int]())((total, next) => if (total.count(_ == next) >= 2) total else total :+ next)
With an answer of:
res9: List[Int] = List(1, 2, 3, 1, 3, 2, 5)
Not the prettiest. I look forward to seeing the other solutions.
def noMoreThan(xs: List[Int], max: Int) =
{
def op(m: Map[Int, Int], a: Int) = {
m updated (a, m(a) + 1)
}
xs.scanLeft( Map[Int,Int]().withDefaultValue(0) ) (op).tail
.zip(xs)
.filter{ case (m, a) => m(a) <= max }
.map(_._2)
}
scala> noMoreThan(l1, 2)
res0: List[Int] = List(1, 2, 3, 1, 3, 2, 5)
More straightforward version using foldLeft:
l1.foldLeft(List[Int]()){(acc, el) =>
if (acc.count(_ == el) >= 2) acc else el::acc}.reverse
Similar to how distinct is implemeted, with a multiset instead of a set:
def noMoreThan[T](list : List[T], max : Int) = {
val b = List.newBuilder[T]
val seen = collection.mutable.Map[T,Int]().withDefaultValue(0)
for (x <- list) {
if (seen(x) < max) {
b += x
seen(x) += 1
}
}
b.result()
}
Based on experquisite's answer, but using foldLeft:
def noMoreThanBis(xs: List[Int], max: Int) = {
val initialState: (Map[Int, Int], List[Int]) = (Map().withDefaultValue(0), Nil)
val (_, result) = xs.foldLeft(initialState) { case ((count, res), x) =>
if (count(x) >= max)
(count, res)
else
(count.updated(x, count(x) + 1), x :: res)
}
result.reverse
}
distinct is defined for SeqLike as
/** Builds a new $coll from this $coll without any duplicate elements.
* $willNotTerminateInf
*
* #return A new $coll which contains the first occurrence of every element of this $coll.
*/
def distinct: Repr = {
val b = newBuilder
val seen = mutable.HashSet[A]()
for (x <- this) {
if (!seen(x)) {
b += x
seen += x
}
}
b.result()
}
We can define our function in very similar fashion:
def distinct2[A](ls: List[A]): List[A] = {
val b = List.newBuilder[A]
val seen1 = mutable.HashSet[A]()
val seen2 = mutable.HashSet[A]()
for (x <- ls) {
if (!seen2(x)) {
b += x
if (!seen1(x)) {
seen1 += x
} else {
seen2 += x
}
}
}
b.result()
}
scala> distinct2(l1)
res4: List[Int] = List(1, 2, 3, 1, 3, 2, 5)
This version uses internal state, but is still pure. It is also quite easy to generalise for arbitrary n (currently 2), but specific version is more performant.
You can implement the same function with folds carrying the "what is seen once and twice" state with you. Yet the for loop and mutable state does the same job.
How about this:
list
.zipWithIndex
.groupBy(_._1)
.toSeq
.flatMap { _._2.take(2) }
.sortBy(_._2)
.map(_._1)
Its a bit ugly, but its relatively faster
val l1 = List(1, 2, 3, 1, 1, 3, 2, 5, 1)
l1.foldLeft((Map[Int, Int](), List[Int]())) { case ((m, ls), x) => {
val z = m + ((x, m.getOrElse(x, 0) + 1))
(z, if (z(x) <= 2) x :: ls else ls)
}}._2.reverse
Gives: List(1, 2, 3, 1, 3, 2, 5)
Here is a recursive solution (it will stack overflow for large lists):
def filterAfter[T](l: List[T], max: Int): List[T] = {
require(max > 1)
//keep the state of seen values
val seen = Map[T, Int]().withDefaultValue(0)//init to 0
def filterAfter(l: List[T], seen: Map[T, Int]): (List[T], Map[T, Int]) = {
l match {
case x :: xs =>
if (seen(x) < max) {
//Update the state and pass to next
val pair = filterAfter(xs, seen updated (x, seen(x) + 1))
(x::pair._1, pair._2)
} else {
//already seen more than max
filterAfter(xs, seen)
}
case _ => (l, seen)//empty, terminate recursion
}
}
//call inner recursive function
filterAfter(l, seen, 2)._1
}
Here is canonical Scala code to do reduce three or more in a row to two in a row:
def checkForTwo(candidate: List[Int]): List[Int] = {
candidate match {
case x :: y :: z :: tail if x == y && y == z =>
checkForTwo(y :: z :: tail)
case x :: tail =>
x :: checkForTwo(tail)
case Nil =>
Nil
}
}
It looks at the first three elements of the list, and if they are the same, drops the first one and repeats the process. Otherwise, it passes items on through.
Solution with groupBy and filter, without any sorting (so it's O(N), sorting will give you additional O(Nlog(N)) in typical case):
val li = l1.zipWithIndex
val pred = li.groupBy(_._1).flatMap(_._2.lift(1)) //1 is your "2", but - 1
for ((x, i) <- li if !pred.get(x).exists(_ < i)) yield x
I prefer approach with immutable Map:
def noMoreThan[T](list: List[T], max: Int): List[T] = {
def go(tail: List[T], freq: Map[T, Int]): List[T] = {
tail match {
case h :: t =>
if (freq(h) < max)
h :: go(t, freq + (h -> (freq(h) + 1)))
else go(t, freq)
case _ => Nil
}
}
go(list, Map[T, Int]().withDefaultValue(0))
}