I am trying to write a recursive sum function as:
val sumRecursive = (list: List[Int]) => list match {
case Nil => 0
case x::xs => x + sumRecursive(xs)
}
It gives error:
Error:(16, 23) recursive value sumRecursive needs type
case x::xs => x + sumRecursive(xs)
I understand that recursive function needs to declare their return type. But I am not sure how to do it in this code structure.
As it complains for the absence of an explicit type, you can provide it the same way you would specify a classical type (val a: Int = 5):
val sumRecursive: List[Int] => Int =
list => list match {
case Nil => 0
case x::xs => x + sumRecursive(xs)
}
which gives:
scala> sumRecursive(List(1, 2, 3))
res0: Int = 6
To perform the analogy with val a: Int = 5,
a is sumRecursive
Int is List[Int] => Int
5 is list => list match { case Nil => 0; case x::xs => x + sumRecursive(xs) }
Maybe a tail recursive function will be better if your list is too long.
val sumRecursive: (List[Int], Int) => Int =
(list, acc) => list match {
case Nil => acc
case x :: xs => sumRecursive(xs, x + acc)
}
Try this
call it like this:
sumRecursive(List(1, 2, 3, 4, 5), 0)
0 is the accumulator that will be incremented to hold the sum value
As it is asking for the type annotation, in Scala the recursive function are not able to infer the return type of the function so. That’s something we need to do in your case it will be the Int.
Just type annotate the method like this.
val sumRecursive :Int= (list: List[Int]) => list match {
case Nil => 0
case x::xs => x + sumRecursive(xs)}
How Int I think you want to know that.
Suppose you have 3 elements in the list: 1,2,3
sunRecursive(list): Int
It will go into the case x::xs which means
x is the head of the list and xs is the tail.
1st step
So you do 1 + sumRecursive(xs) //xs=2, 3
2nd step 2+sumResursive(xs) //xs=3
3rd step 3 +sumResursive(xs) //xs=Nil
It will go into the first case and return 0.
So 3rd step willreturn 3+0 to the second step
It will become2+3 and return to the 1st step
It will become1+2+3 which is 6 and it will return 6
So the return type will be Int ultimately.
Related
I am trying to run a function in scala
def sum(xs: List[Int]): Int = xs match {
case Nil => throw new java.util.NoSuchElementException("Minimum number of elements")
case x :: xs => x + sum(xs)
}
When I try to run like this,
sum(List(1,2,3))
I am getting the runtime exception
java.util.NoSuchElementException: Minimum number of elements
at .sum(<console>:12)
at .sum(<console>:13)
On the other hand, this works
def sum(xs: List[Int]): Int = xs match {
case Nil => 0
case x :: xs => x + sum(xs)
}
List(1,2,3) is equivalent to 1::2::3::Nil
so your function is evaluated in following order
sum(1::2::3::Nil) = 1 + sum(2::3::Nil)
sum(2::3::Nil) = 2 + sum(3::Nil)
sum(3::Nil) = 3 + sum(Nil)
and at last sum(Nil) throws exception.
You can get more information from following question.
Why is Nil required at the end of a list built using the cons operator
Why do we need Nil while creating List in scala?
I find that I often end up with a list of Options (or Eithers or Trys) and I want to count the number of Nones before I flatten the list. Is there a nice idiomatic way to do this that doesn't require I process the list multiple times?
Something like this but better:
val sprockets: List[Option[Sprockets]] = getSprockets()
println("this many sprockets failed to be parsed" + sprockets.filter(_.isEmpty).count)
println(sprockets.flatten)
I would have used a fold as Daenyth suggested, for example somthing like this:
val list = List(Some(1),None,Some(0),Some(3),None)
val (flatList,count) = list.foldLeft((List[Int](),0)){
case ((data,count), Some(x)) => (data :+ x, count)
case ((data,count), None) => (data, count +1)
}
//output
//flatList: List[Int] = List(1, 0, 3)
//count: Int = 2
Recursion maybe?
#tailrec
def flattenAndCountNones[A](in: Seq[Option[A]], out: Seq[A] = Queue.empty[A], n: Int = 0): (Seq[A], Int) = in match {
case Nil => (out, n)
case Some(x) :: tail => flattenAndCountNones(tail, out :+ x, n)
case None :: tail => flattenAndCountNones(tail, out, n + 1)
}
Is this what you're looking for?
val foo = List(Some(3), Some(4), None:Option[Int], Some(5), Some(6))
val (concatenatedList, emptyCount) =
foo.map(entry =>
(entry.toList, if (entry.isEmpty) 1 else 0)
).fold((List[Int](), 0))((a, b) =>
(a._1 ++ b._1, a._2 + b._2)
)
It is one pass, but I'm not sure if it's really any more efficient than doing it in two - the extra object creation (the Tuple2s) in this case is going to offset the extra loop in the two-pass case.
I know that parametric polymorphism is what actually works, but I'm curious why using Any in it's place does not. For example how is the first function
def len[T] (l:List[T]):Int =
l match {
case Nil => 0
case _ :: t => 1 + len(t)
}
different from this one?
def len (l:List[Any]):Int =
l match {
case Nil => 0
case _ :: t => 1 + len(t)
}
What do you mean it doesn't work? This seems fine:
len(List('a,'b,'c))
// res0: Int = 3
Your in your example, there really isn't a difference, since you're not actually using the contents of the list for anything, but imagine a slightly different function:
def second[T](l: List[T]): Option[T] =
l match {
case Nil => None
case _ :: Nil => None
case _ :: x :: _ => Some(x)
}
println(second(List(1,2,3)).map(_ + 5)) // Some(7)
println(second(List(List('a,'b,'c), List('d,'e))).map(_.head)) // Some('d)
If you tried this with Any, you wouldn't be able to get anything except Option[Any] in return, so the compiler wouldn't let you do anything useful with the result (like add it to an Int or call .head, as in the examples, respectively).
In this case there really isn't a difference, because you aren't relying on the contained type at all, just the structure of List itself. It doesn't matter what T is, the length will be the same either way.
The type parameter would be important if you wanted to return another List[T]. For example:
def takeEveryOther[T](l: List[T]): List[T] =
l.zipWithIndex.collect { case (a, i) if(i % 2 == 0) => a }
Let's say I have this collection:
val a = Array(Array(1,2,3,4,5),Array(4,5),Array(5),Array(1,2,6,7,8))
Is there a way to define an extractor which would work in the following way:
a.foreach(e => {
e match {
case Array( ending with 5 ) =>
case _ =>
}
})
Sorry for the pseudocode, but I don't know how to express it. Is there a way to match something having 5 as the last element? What if I would want to match something having a 1 as the first element and a 5 as the last? Could this work for arrays of various lengths ( note that I specifically chose different lengths for my arrays in the example ).
Thanks!
Yes you can:
object EndsWith {
def unapply[A]( xs: Array[A] ) =
if( xs.nonEmpty ) Some( xs.last ) else None
}
On your example:
val a = Array(Array(1,2,3,4,5),Array(4,5),Array(5),Array(1,2,6,7,8))
a foreach {
case e # EndsWith(5) => println( e.mkString("(",",",")" ) )
case _ =>
}
It prints as expected (1,2,3,4,5), (4,5) and (5)
With the same approach, you could write an extractor StartWith and then add a method to combine them in a new extractor matching both conditions.
a.foreach(e => {
e match {
case a: Array[Int] if a.last == 5 =>
case _ =>
}
})
You can do something a little better for matching on the first elements:
a.foreach(e => {
e match {
case Array(1, _*) =>
case _ =>
}
})
Unfortunately the #_* thing has to be the last item in the list of array arguments. But you can make the matching before that as complex as you want.
scala> val Array(1, x #_*) = Array(1,2,3,4,5)
x: Seq[Int] = Vector(2, 3, 4, 5)
scala> val Array(1, b, 3, x #_*) = Array(1,2,3,4,5)
b: Int = 2
x: Seq[Int] = Vector(4, 5)
The case syntax supports ifs, so this would work:
a foreach {
case a: Array[Int] if a.last == 5 =>
case _ =>
}
a.foreach (ar => ar.last match {
case 5 => println ("-> 5] " + ar.mkString ("~"))
case _ => println (" ?] " + ar.mkString (":")) })
Why don't you match directly for the last element?
-> 5] 1~2~3~4~5
-> 5] 4~5
-> 5] 5
?] 1:2:6:7:8
I've an initial list that consists in different types of elements and I've to filter it to just take the int and double values.
For example (1 :: "hello" :: 100 :: 3.14 :: ('a'::10::Nil) :: 'c' :: (5,7,'a') :: Nil) should become (1, 100, 3.14, List(10), (5,7))
I'm having trouble coming up with a solution because once the list is passed to a method it becomes a List[Any] type of list and I need to know the type of each element before casting it. It wouldn't be a problem it didn't contain others substructures such as tuples as I could manage something with a pattern matching.
Is it possible somehow to get the specific type of a Any element and to cast it?
As an academic exercise it's rather silly. You should be learning how to avoid situations like this instead of trying to deal with it. Still, bad code can be rather instructive at times.
def intOrDbl(la :List[Any]) :List[Any] = la.flatMap{
case i:Int => List(i)
case d:Double => List(d)
case l:List[_] => List(intOrDbl(l))
case t:Product => val res = intOrDbl(t.productIterator.toList)
res.length match {
case 0 => Nil
case 1 => List(res)
case 2 => List((res(0),res(1)))
case 3 => List((res(0),res(1),res(2)))
case 4 => List((res(0),res(1),res(2),res(3)))
// etc.
}
case _ => Nil
}
val data = 1 :: "hello" :: 100 :: 3.14 :: ('a'::10::Nil) :: 'c' :: (5,7,'a') :: Nil
intOrDbl(data)
//res0: List[Any] = List(1, 100, 3.14, List(10), (5,7))
One choice you have is to put your result type into an ADT. Here is how it might work:
sealed trait IntOrDoubleOrList
case class IntValue(value: Int) extends IntOrDoubleOrList
case class DoubleValue(value: Double) extends IntOrDoubleOrList
case class ListValue(value: List[IntOrDoubleOrList]) extends IntOrDoubleOrList
def filterIntOrDouble(l: List[_]): List[IntOrDoubleOrList] = {
l.collect({
case iv: Int => IntValue(iv)
case dv: Double => DoubleValue(dv)
case lv: List[_] => ListValue(filterIntOrDouble(lv))
})
}
def test(): Unit = {
val origList = (1 :: "hello" :: 100 :: 3.14 :: ('a' :: 10 :: Nil) :: 'c' :: (5, 7, 'a') :: Nil)
val f = filterIntOrDouble(origList)
println(f)
}
Depending on you further needs you may extend the IntOrDoubleOrList trait with some helper methods like foreach(intHandler: Int => Unit, doubleHandler: Double => Unit)