Add to list nth times depending of element's value - scala

I want to write a function which will add an element n to a list n times for all elements in an input list.
For example:
L = List(2,4,1)
Output should be:
List(2,2,4,4,4,4,1)
I would like to do it with tail recursion. So far, I have written this:
def repeat(numbers: List[Int]): List[Int] = {
def repeat_acc(numbers: List[Int], acc: List[Int], number_acc: Int): List[Int] = {
if (numbers.length == 0)
return acc
else if (number_acc == 0)
repeat_acc(numbers.tail, acc, numbers.head)
else
repeat_acc(numbers, acc :+ numbers.head, (number_acc-1))
}
repeat_acc(numbers, List(), 0)
}
The problem is that it leaves out the first element of the list. For this output will be:
(4, 4, 1, 1, 1, 1)
I know why it happens, but I cannot fix it. I have tried many other ways, but for me it seems that tail recursion do not work here. Some always goes wrong, and I get the wrong result.
Thanks for any advice.

I know you want to do a personalized tail recursive call, but I would recommend the following instead:
def repeat(numbers: List[Int]): List[Int] = {
numbers.flatMap(n => List.fill(n)(n))
}
The inner function takes the value n and repeats it n times in a list, and then this function is flat mapped onto the original list (a regular map would turn List(1,2,3) into List(List(1), List(2, 2), List(3, 3, 3)), so we use flat map). This has the benefit of 'doing it the Scala way' with built in collections functionality.

This problem gets a lot simpler if you add another parameter to your inner recursive method, representing the current number being added. You should also familiarize yourself with match statements, since they are really powerful in Scala and can help express exactly this type of logic. Nested if/else statements and early return statements are considered unidiomatic. Try:
def repeat(numbers: List[Int]) = {
def repeatAcc(acc: List[Int], curr: Int, rem: Int, numbers:List[Int]): List[Int] =
(numbers, rem) match {
case (Nil, 0) => acc
case (hd::tl, 0) => repeatAcc(acc, hd, hd, tl)
case (_, n) => repeatAcc(acc :+ curr, curr, n - 1, numbers)
}
repeatAcc(List.empty[Int], 0, 0, numbers)
}
You might also try to use some standard Scala methods like List.fill, which can be used in conjunction with the tail recursion as follows:
def repeat(numbers: List[Int]) = {
def repeatAcc(acc: List[Int], numbers:List[Int]): List[Int] = numbers match {
case hd::tl => repeatAcc(acc ++ List.fill(hd)(hd), tl)
case Nil => acc
}
repeatAcc(List.empty[Int], numbers)
}
Finally, I understand you're trying to learn about these core concepts, but it should be mentioned that this is really simple with Scala built ins:
(List.empty[Int] /: numbers) { case (soFar, next) => soFar ++ List.fill(next)(next) }
numbers.flatMap(x => List.fill(x)(x))

Try this, it works
import scala.annotation.tailrec
#tailrec
def f(l: List[Int], res: List[Int] = Nil): List[Int] = {
#tailrec
def g(n: Int, acc: List[Int]): List[Int] = {
if (n == 1) acc
else g(n - 1, acc :+ acc.head)
}
if (l == Nil) res else f(l.tail, res ++ g(l.head, List(l.head)))
}
scala> f(List(1,2,3))
res0: List[Int] = List(1, 2, 2, 3, 3, 3)

Ok, I find the solution. Looks bad, but works. I'm too tired to figure out something better.
Here is my code:
def repeat(numbers: List[Int]): List[Int] = {
def repeat_acc(numbers: List[Int], acc: List[Int], number_acc: Int): List[Int] = {
if (numbers.length == 1 && number_acc == 0)
return acc
else if (acc.length == 0)
repeat_acc(numbers, acc :+ numbers.head, (number_acc-1))
else if (number_acc == 0 && numbers.tail != Nil ){
repeat_acc(numbers.tail, acc, (numbers.tail.head))
}
else
repeat_acc(numbers, acc :+ numbers.head, (number_acc-1))
}
repeat_acc(numbers, List(), numbers.head)
}

simple, just use fill + flatMap
val result = L.flatMap(x => List.fill(x)(x))
for recursive solution :
scala> def repeat(numbers: List[Int]): List[Int] = {
def run(nums:List[Int]):List[Int] ={
nums match {
case Nil => List.empty[Int]
case x::Nil => List.fill(x)(x)
case x::xs => List.fill(x)(x):::run(xs)
}}
run(numbers)
}
scala> repeat(List(2,4,1))
res1: List[Int] = List(2, 2, 4, 4, 4, 4, 1)

Related

sum elements in scala List[List[Int]]

how to sum of elements in Scala List[List[Int]]
example :
val mylist = List(List(1,2,3),List(2,3,4))
output :
List(List(6),List(9))
If you want the result list to be of type List[List[Int]] and not List[Int], you can achieve it by doing this:
mylist.map(l => l.foldLeft(List(0))((acc, el) => List(acc(0) + el)))
Since mylist.map(_.sum) will result in an List[Int] you can also do it this way:
mylist.map(_.sum).map(List(_))
And if you really want to achieve it without the scala collection library, you can do it with recursion:
object Appz extends App {
val mylist: List[List[Int]] = List(List(2,2,3),List(2,3,4))
def sumSubLists(ll: List[List[Int]]): List[Int] = {
#annotation.tailrec
def sumList(l: List[Int], acc: Int = 0): Int = l match {
case List() => acc
case h :: t => sumList(t, acc + h)
}
#annotation.tailrec
def sumSubListsInner(ll: List[List[Int]], acc: List[Int]): List[Int] =
ll match {
case List() => acc
case h :: t => sumSubListsInner(t, acc ++ List(sumList(h)))
}
sumSubListsInner(ll, List())
}
println(sumSubLists(mylist))
}

How fix type mismatch using tail recursion?

I need to group one list into two by index numbers, if it odd to first list, if even to second.
Here is my function
def group2(list: List[Int]): (List[Int], List[Int]) = {
def group2Helper(list: List[Int], listA: List[Int], listB: List[Int]): (List[Int], List[Int]) = list match {
case Nil => (listA, listB)
case head :: tail => group2Helper(tail.tail, listA ::: List(head), listB ::: List(tail.head))
}
}
group2(List(2, 6, 7, 9, 0, 4, 1))
As result it have to return (List(2, 7, 0, 1), List(6, 9, 4))
Now I have problem: "Type mismatch, found: Unit, required: (List[Int], List[Int])", that highlighted at last brace
After you fix the missing group2helper() invocation your code still won't work because you're processing the input two at a time, but the input List has an odd number of elements so that will cause a runtime error.
A different approach is to process the input one at a time and keep swapping which list gets added to.
def group2(list: List[Int]): (List[Int], List[Int]) = {
def group2Helper(list: List[Int], listA: List[Int], listB: List[Int]): (List[Int], List[Int]) = list match {
case Nil => (listA.reverse, listB.reverse)
case hd :: tl => group2Helper(tl, listB, hd :: listA)
}
group2Helper(list, Nil, Nil)
}
group2(List(2, 6, 7, 9, 0, 4, 1))
//res0: (List[Int], List[Int]) = (List(6, 9, 4),List(2, 7, 0, 1))
Two things worth noting: 1) When building a List it is often more efficient to pre-pend (i.e. build it backwards) and then reverse the result, and 2) the order of the output lists will depend on whether the input has an even or odd number of elements, but the content of each output List will be correct.
OK, so there's a simple fix for the order-of-output-lists problem.
def group2(list: List[Int]): (List[Int], List[Int]) = {
def group2Helper(list: List[Int], listA: List[Int], listB: List[Int]): (List[Int], List[Int]) = list match {
case Nil => (listA.reverse, listB.reverse)
case hd :: Nil => ((hd::listA).reverse, listB.reverse)
case a :: b :: tl => group2Helper(tl, a::listA, b::listB)
}
group2Helper(list, Nil, Nil)
}
This is a return to the original two-at-a-time processing, but with two different termination patterns.
group2 defines a function, but doesn't actually execute it. After you define group2helper, make sure you call it and you should be fine.

Remove Duplicates from the List recursively

I want to remove duplicates from the list recursively using pattern matching with Scala
here is my input
val xs = List(1,2,3,4,6,3,2,7,9,4)
Tried code:
def removeDuplicates(xs : List[Int]) : List[Int] = xs match {
case Nil =>Nil
case x::ys => {
if(ys.contains(x)){
removeDuplicates(ys)
} else {
}
/// ???
}
}
I was stuck at the question mark, how to appened my result to the mutable list and return it.
Thank you.
You're close:
def removeDuplicates(xs : List[Int]) : List[Int] = xs match {
case Nil => Nil
case x::ys => if (ys.contains (x)) removeDuplicates (ys) else
x :: removeDuplicates (ys)
}
scala> removeDuplicates (List (1,2,3,4,6,3,2,7,9,4))
res143: List[Int] = List(1, 6, 3, 2, 7, 9, 4)
While this is a brief solution, it isn't tail recursive and therefore vulnerable for stackoverflows - whereas Jean Logearts solution solves the problem.
Here is an alternative solution with an inner function, tailrecursive too:
def removeDuplicates (xsOuter : List[Int]) : List[Int] = {
#annotation.tailrec
def removeDuplicates (xs: List[Int], collected: List[Int]) : List[Int] = xs match {
case Nil => collected
case x :: ys => if (collected.contains (x)) removeDuplicates (ys, collected) else
removeDuplicates (ys, x :: collected)
}
removeDuplicates (xsOuter, Nil)
}
scala> removeDuplicates (List (1,2,3,4,6,3,2,7,9,4))
res151: List[Int] = List(9, 7, 6, 4, 3, 2, 1)
with a bias to the first elements, but with the result reversed, which can be easily corrected by returning collected.reverse in the Nil case, if it is important.
The outer function serves the job to provide a simple, one-argument interface to the user, so he doesn't need to provide an empty List.
Note, that the solution is crying for a type annotation, since it doesn't depend at all on the List elements being of type Int:
scala> def removeDuplicates [A] (xsOuter : List[A]) : List[A] = {
|
| #annotation.tailrec
| def removeDuplicates (xs: List[A], collected: List[A]) : List[A] = xs match {
| case Nil => collected
| case x :: ys => if (collected.contains (x)) removeDuplicates (ys, collected) else
| removeDuplicates (ys, x :: collected)
| }
|
| removeDuplicates (xsOuter, Nil)
| }
removeDuplicates: [A](xsOuter: List[A])List[A]
scala> removeDuplicates (List (1,2,3,4,6,3,2,7,9,4))
res152: List[Int] = List(9, 7, 6, 4, 3, 2, 1)
You need to keep track of the current state: already seen elements using a set (for fast lookup), and the new list being constructed:
#tailrec
def removeDuplicatesRec(
remaining: List[Int],
seen: Set[Int],
acc: List[Int]
): List[Int] = remaining match {
case Nil => acc
case head :: tail =>
if (!seen.contains(head)) removeDuplicatesRec(tail, seen + head, acc :+ head)
else removeDuplicatesRec(tail, seen, acc)
}
def removeDuplicates(xs: List[Int]): List[Int] =
removeDuplicatesRec(xs, Set.empty, List.empty)
Here's a classic approach using an inner function and tail recursion. The tail recursion may not be necessary for small lists but it is easier for me to reason about.
def removeDuplicates(xs : List[Int]) : List[Int] = {
#scala.annotation.tailrec
def accumulator(xs: List[Int], acc: List[Int]):List[Int] = xs match {
case Nil => acc
case h::t if(!acc.contains(h)) => accumulator(t, h :: acc)
case h::t if(acc.contains(h)) => accumulator(t, acc)
}
accumulator(xs, List[Int]())
}
scala> removeDuplicates(List(1,2,3,4,6,3,2,7,9,4))
res16: List[Int] = List(9, 7, 6, 4, 3, 2, 1)
Of course, distinct is the preferred way to do this but this is a good exercise. distinct can be used to verify your solution though.
scala> List(1,2,3,4,6,3,2,7,9,4).distinct == removeDuplicates(List(1,2,3,4,6,3,2,7,9,4)).sorted
res21: Boolean = true

Recursively iterate through a Scala list

I'm trying to recursively iterate through a list in Scala using pattern matching. I cannot use any list functions, or while/for loops. What I need to do is iterate through the list, and remove an element if it matches to be '4'. I'm new to Scala and I cannot find the answer in the textbook I have nor on google. Everyone else uses the filter method, or some other list method.
Here's what I tried to do (which is wrong)
def removeFours(lst: List[Int]): List[Int] = {
val newLst = lst
lst match {
case Nil => Nil
case a if a == 4 => newLst -= 0
case n => removeFours(newLst)
}
newLst
}
See if this works for you.
def removeFours(lst: List[Int], acc: List[Int] = List.empty): List[Int] = {
lst match {
case Nil => acc.reverse
case 4 :: t => removeFours( t, acc )
case h :: t => removeFours( t, h :: acc )
}
}
Usage:
scala> removeFours( List(3,7,4,9,2,4,1) )
res84: List[Int] = List(3, 7, 9, 2, 1)
Using an inner function and pattern matching to de-structure the list. If the head in the list is 4, then do not add it to the accumulator. If it is, append it to the accumulator.
def removeFours(lst: List[Int]): List[Int] = {
def loop(lst: List[Int], acc: List[Int]): List[Int] = lst match {
case Nil => acc
case h :: t =>
if (h == 4) {
loop(t, acc)
}else{
loop(t, acc :+ h)
}
}
loop(lst, List())
}
The preferred way to do this is with guards in the pattern match but the if else statement may look more familiar if you're just getting started with scala.
def removeFours(lst: List[Int]): List[Int] = {
def loop(lst: List[Int], acc: List[Int]): List[Int] = lst match {
case Nil => acc
case h :: t if (h == 4) => loop(t, acc)
case h :: t => loop(t, acc :+ h)
}
loop(lst, List())
}
I am not sure about the execution time. I am also new to scala but I am taking bollean approach to filter any list.
object Main extends App {
//fun that will remove 4
def rm_4(lst: List[Int]) : List[Int] = {
val a = lst.filter(kill_4)
a
}
// boolean fun for conditions
def kill_4(n: Int) : Boolean = {
if (n ==4) false
else true
}
println(rm_4(List(1,2,4,5,4))) // outpur List(1,2,5)
}

List of every n-th item in a given list

This is a simple exercise I am solving in Scala: given a list l return a new list, which contains every n-th element of l. If n > l.size return an empty list.
def skip(l: List[Int], n: Int) =
Range(1, l.size/n + 1).map(i => l.take(i * n).last).toList
My solution (see above) seem to work but I am looking for smth. simpler. How would you simplify it?
Somewhat simpler:
scala> val l = (1 to 10).toList
l: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// n == 3
scala> l.drop(2).grouped(3).map(_.head).toList
res0: List[Int] = List(3, 6, 9)
// n > l.length
scala> l.drop(11).grouped(12).map(_.head).toList
res1: List[Int] = List()
(the toList just to force the iteratot to be evaluated)
Works with infinite lists:
Stream.from(1).drop(2).grouped(3).map(_.head).take(4).toList
res2: List[Int] = List(3, 6, 9, 12)
scala> def skip[A](l:List[A], n:Int) =
l.zipWithIndex.collect {case (e,i) if ((i+1) % n) == 0 => e} // (i+1) because zipWithIndex is 0-based
skip: [A](l: List[A], n: Int)List[A]
scala> val l = (1 to 10).toList
l: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> skip(l,3)
res2: List[Int] = List(3, 6, 9)
scala> skip(l,11)
res3: List[Int] = List()
A bit more readable and the loop size is O(l.length/n):
def skip(l: List[Int], n: Int) = {
require(n > 0)
for (step <- Range(start = n - 1, end = l.length, step = n))
yield l(step)
}
Fold left approach O(n)
def skip(xs: List[Int], n: Int) = {
xs.foldLeft((List[Int](), n)){ case ((acc, counter), x) =>
if(counter==1)
(x+:acc,n)
else
(acc, counter-1)
}
._1
.reverse
}
scala > skip(List(1,2,3,4,5,6,7,8,9,10), 3)
Tailrec less readable approach O(n)
import scala.annotation.tailrec
def skipTR(xs: List[Int], n: Int) = {
#tailrec
def go(ys: List[Int], acc: List[Int], counter: Int): List[Int] = ys match {
case k::ks=>
if(counter==1)
go(ks, k+:acc , n)
else
go(ks, acc, counter-1)
case Nil => acc
}
go(xs, List(), n).reverse
}
skipTR(List(1,2,3,4,5,6,7,8,9,10), 3)
You could omit toList if you don't mind an iterator:
scala> def skip[A](l:List[A], n:Int) =
l.grouped(n).filter(_.length==n).map(_.last).toList
skip: [A](l: List[A], n: Int)List[A]
scala> skip (l,3)
res6: List[Int] = List(3, 6, 9)
Two approaches based in filter on indexes, as follows,
implicit class RichList[A](val list: List[A]) extends AnyVal {
def nthA(n: Int) = n match {
case 0 => List()
case _ => (1 to a.size).filter( _ % n == 0).map { i => list(i-1)}
}
def nthB(n: Int) = n match {
case 0 => List()
case _ => list.zip(Stream.from(1)).filter(_._2 % n == 0).unzip._1
}
}
and so for a given list
val a = ('a' to 'z').toList
we have that
a.nthA(5)
res: List(e, j, o, t, y)
a.nthA(123)
res: List()
a.nthA(0)
res: List()
Update
Using List.tabulate as follows,
implicit class RichList[A](val list: List[A]) extends AnyVal {
def nthC(n: Int) = n match {
case 0 => List()
case n => List.tabulate(list.size) {i =>
if ((i+1) % n == 0) Some(list(i))
else None }.flatten
}
}