Passing Empty List of List Argument - scala

I worked on the "Pack Function" exercise from "Functional Programming Principles in Scala".
Put consecutive duplicates into a List[List[T]].
Example
input: List("a", "a", "b", "b", "c", "a")
output: List(List(a, a), List(b, b), List(c), List(a))
Given this function...
def pack[T](xs: List[T]): List[List[T]] = {
def go[T](ys: List[T], acc: List[List[T]]) : List[List[T]] = ys match {
case Nil => acc
case x :: xs_ => val r: List[T] = ys.takeWhile(a => a == x)
go(ys.drop(r.length), acc :+ r)
}
go(xs, List(Nil).filter(_ != Nil)) // *** line in question ***
}
Is there a better way to pass in a List[List[T]] where the inner list is empty?
If I didn't have the filter there, the head of pack(...)'s result would be List().

Why not just...........:
go(xs, Nil)
BTW, there is my solution for this problem:
def pack[T](xs: List[T],
acc: List[List[T]] = Nil): List[List[T]] =
(xs, acc) match {
case (Nil, _) => acc
case (i:+last, (h::t1)::t2) if last == h => pack(i, (last::h::t1)::t2)
case (i:+last, acc0) => pack(i, List(last)::acc0)
}
And here is another solution:
def pack[T](xs: List[T]): List[List[T]] = xs match {
case Nil => Nil
case x::rs => pack(rs) match {
case (h#`x`::_)::t => (x::h)::t
case t => List(x)::t
}
}

Related

What to set as default when the type is A (Scala)

I have an exercise in Scala in which I have to transform that kind of list (a,a,a,b,c,d,d,e,a,a) into
((a,3),(b,1),(c,1),(d,2),(e,1),(a,2)).
I obviously know that my algorithm is not correct yet, but I wanted to start with anything.
The problem is that I don't know how to turn on the function (last line), because the error is that whatever I take as previous' argument, it says that required: A, found: Int/String etc.
The previous was meant to be as a head of the previous iteration.
def compress[A](l: List[A]): List[(A, Int)] = {
def compressHelper(l: List[A], acc: List[(A, Int)], previous: A, counter: Int): List[(A, Int)] = {
l match {
case head::tail => {
if (head == previous) {
compressHelper(tail, acc :+ (head, counter+1), head, counter+1)
}
else {
compressHelper(tail, acc :+ (head, counter), head, 1)
}
}
case Nil => acc
}
}
compressHelper(l, List(), , 1)
}
You don't need to pass previous explicitly, just look at the accumulator:
def compress[A](l: List[A], acc: List[(A, Int)]=Nil): List[(A, Int)] =
(l, acc) match {
case (Nil, _) => acc.reverse
case (head :: tail, (a, n) :: rest) if a == head =>
compress(tail, (a, n+1) :: rest)
case (head :: tail, _) => compress (tail, (head, 1) :: acc)
}

Filter from Seq less/greater elements and only one equal

I want to implement method in Scala which filters from Seq elements which are for example greater than provided value and additionally returns up to one equal element. For example:
greaterOrEqual(Seq(1,2,3,3,4), 3) shouldBe Seq(3,4)
I ended up with such method:
def greaterOrEqual(
seq: ArrayBuffer[Long],
value: Long
): ArrayBuffer[Long] = {
val greater = seq.filter(_ > value)
val equal = seq.filter(_ == value)
if (equal.isEmpty) {
greater
} else {
equal.tail ++ greater
}
}
but somehow it doesn't look nice to me :) Moreover, I'd like to have generic version of this method where I'd able to use not only Long type but custom case classes.
Do you have any suggestions?
Thanks in advance.
def foo[A : Ordering[A]](seq: Seq[A], value: A) = seq.find(_ == value).toList ++ seq.filter(implicitly[Ordering[A]].gt(_,value))
Or (different style)
def foo[A](seq: Seq[A], value: A)(implicit ord: Ordering[A]) = {
import ord._
seq.find(_ == value).toList ++ seq.filter(_ > value)
}
The code below is deprecated
scala> def foo[A <% Ordered[A]](seq: Seq[A], value: A) = seq.find(_ == value).toList ++ seq.filter(_ > value)
foo: [A](seq: Seq[A], value: A)(implicit evidence$1: A => Ordered[A])List[A]
scala> foo(Seq(1,2,3,3,4,4,5),3)
res8: List[Int] = List(3, 4, 4, 5)
Here's my take on it (preserving original order).
import scala.collection.mutable.ArrayBuffer
def greaterOrEqual[A]( seq :ArrayBuffer[A], value :A
)(implicit ord :Ordering[A]
) : ArrayBuffer[A] =
seq.foldLeft((ArrayBuffer.empty[A],true)){
case (acc, x) if ord.lt(x,value) => acc
case ((acc,bool), x) if ord.gt(x,value) => (acc :+ x, bool)
case ((acc,true), x) => (acc :+ x, false)
case (acc, _) => acc
}._1
testing:
greaterOrEqual(ArrayBuffer.from("xawbaxbt"), 'b')
//res0: ArrayBuffer[Char] = ArrayBuffer(x, w, b, x, t)
This is an excellent problem for a simple tail-recursive algorithm over lists.
def greaterOrEqual[T : Ordering](elements: List[T])(value: T): List[T] = {
import Ordering.Implicits._
#annotation.tailrec
def loop(remaining: List[T], alreadyIncludedEqual: Boolean, acc: List[T]): List[T] =
remaining match {
case x :: xs =>
if (!alreadyIncludedEqual && x == value)
loop(remaining = xs, alreadyIncludedEqual = true, x :: acc)
else if (x > value)
loop(remaining = xs, alreadyIncludedEqual, x :: acc)
else
loop(remaining = xs, alreadyIncludedEqual, acc)
case Nil =>
acc.reverse
}
loop(remaining = elements, alreadyIncludedEqual = false, acc = List.empty)
}
Which you can use like this:
greaterOrEqual(List(1, 3, 2, 3, 4, 0))(3)
// val res: List[Int] = List(3, 4)
You can use the below snippet:
val list = Seq(1,2,3,3,4)
val value = 3
list.partition(_>=3)._1.toSet.toSeq
Here partition method divide the list into two list. First list which satisfy the given condition, and second list contains the remaining elements.
For generic method you can using implicit Ordering. Any type who can compare elements can be handled by greaterOrEqual method.
import scala.math.Ordering._
def greaterOrEqual[T](seq: Seq[T], value: T)(implicit ordering: Ordering[T]): Seq[T] = {
#scala.annotation.tailrec
def go(xs: List[T], value: T, acc: List[T]): List[T] = {
xs match {
case Nil => acc
case head :: rest if ordering.compare(head, value) == 0 => rest.foldLeft(head :: acc){
case (result, x) if ordering.compare(x, value) > 0 => x :: result
case (result, _) => result
}
case head :: rest if ordering.compare(head, value) > 0 => go(rest, value, head :: acc)
case _ :: rest => go(rest, value, acc)
}
}
go(seq.toList, value, List.empty[T]).reverse
}

How to replace or append an item in/to a list?

Suppose I've got a list of case class A(id: Int, str: String) and an instance of A. I need to either replace an item from the list with the new instance or append the new instance to the list.
case class A(id: Int, str: String)
def replaceOrAppend(as: List[A], a: A): List[A] = ???
val as = List(A(1, "a1"), A(2, "a2"), A(3, "a3"))
replaceOrAppend(as, A(2, "xyz")) // List(A(1, "a1"), A(2, "xyz"), A(3, "a3"))
replaceOrAppend(as, A(5, "xyz")) // List(A(1, "a1"), A(2, "a2"), A(3, "a3"), A(5, "xyz"))
I can write replaceOrAppend like this:
def replaceOrAppend(as: List[A], a: A): List[A] =
if (as.exists(_.id == a.id)) as.map(x => if (x.id == a.id) a else x) else as :+ a
This implementation is a bit clumsy and obviously suboptimal since it passes the input list twice. How to implement replaceOrAppend to pass the input list just once ?
If the order is not essential I would go with:
def replaceOrAppend(as: List[A], a: A): List[A] =
a::as.filterNot(_.id == a.id)
This would also work if the order is related to id or str:
def replaceOrAppend(as: List[A], a: A): List[A] =
(a::as.filterNot(_.id == a.id)).sortBy(_.id)
And if the order must be kept (as Micheal suggested - I couldn't find anything better):
def replaceOrAppend(as: List[A], a: A): List[A] =
as.span(_.id != a.id) match { case (xs, ys) => xs ++ (a :: ys.drop(1)) }
Here is another one:
def replaceOrAppend(as: List[A], a: A): List[A] = {
as.find(_.id==a.id).map(op => {
as.map(el => el match {
case e if e.id==a.id => e.copy(str=a.str)
case _ => el
})
}).getOrElse((a::as.reverse).reverse)
}
What about this? Still clumsy but only uses one iteration.
def replaceOrAppend(as: List[A], a: A): List[A] = {
val (updatedList,itemToAppend) = as.foldLeft((List[A](),Option(a))) {
case ((acc, Some(item)), l) =>
if (item.id == l.id) (acc :+ item, None)
else (acc :+ l, Some(item))
case ((acc, None), l) => (acc :+ l, None)
}
itemToAppend match {
case Some(item) => updatedList :+ item
case None => updatedList
}
}
I do not understand why people forgets that the best way to handle a functional list is through pattern matching + tail-recursion.
IMHO, this looks cleaner and tries to be as efficient as possible.
final case class A(id: Int, str: String)
def replaceOrAppend(as: List[A], a: A): List[A] = {
#annotation.tailrec
def loop(remaining: List[A], acc: List[A]): List[A] =
remaining match {
case x :: xs if (x.id == a.id) =>
acc reverse_::: (a :: xs)
case x :: xs =>
loop(remaining = xs, acc = x :: acc)
case Nil =>
(a :: acc).reverse
}
loop(remaining = as, acc = List.empty)
}
technically speaking, this traverse the list twice on the worst case.
But, it is always better to build a list by prepending from the head and reverse at the end, than to do many appends.

Why the first element missing when using the function span?

The function below generates a List
def pack[T](xs: List[T]): List[List[T]] = xs match {
case Nil => Nil
case x::xs =>
val (first, rest) = xs span(y => y==x)
first::pack(rest)
}
When applying pack on a list
val lis4 = List("a", "a", "a", "b", "c", "c", "a")
I get a result
res3: List[List[String]] = List(List(a, a), List(), List(c), List())
However, according to the course given by Martin Odersky on coursera,
it should generate a result
Can anyone tell me what's wrong?
You're shadowing xs defined at the method level with the local binding of xs inside the pattern match. Notice in Oderskys example, the local pattern match bind is called xs1:
def pack[T](xs: List[T]): List[List[T]] = xs match {
case Nil => Nil
case x :: xs1 =>
val (first, rest) = xs span(y => y == x)
first :: pack(rest)
}
To make this even clearer, you can ignore the tail part of the list in the pattern match using _:
def pack[T](xs: List[T]): List[List[T]] = xs match {
case Nil => Nil
case x :: _ =>
val (first, rest) = xs span(y => y == x)
first :: pack(rest)
}
Yields:
scala> pack(List("a", "a", "a", "b", "c", "c", "a"))
res2: List[List[String]] = List(List(a, a, a), List(b), List(c, c), List(a))

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)
}