def third_list[A](ls: List[A]): A = {
// Code can be changed here
return List(ls(2)) //Error line for return type
}
val l1 = List(1, 2, 3, 4)
println(third_list(l1))
println(third_list(List(1,2,(3,4,5), 6, 7)))
I need to return 3rd element of the list following the return type criteria.
I am getting type mismatch error:
Required A found list[A]
Shouldn't ls(2) return an element type already?
The simple answer to the question is to use lift:
def third_list[A](ls: List[A]): Option[A] =
ls.lift(2)
This returns an Option because you really want your code to work even if the list doesn't have three elements. Process the data inside the Option or use getOrElse to specify a default.
You are returning a List with elements of type A therefore you are returning a List[A] value, but the return type you have set for that method is A and they do not match.
You have declared the return type of third_list as A, but you are extracting an element of type A (ls(2)), wrapping it in a new list (List(ls(2)), and returning that instead. Also, your code will fail if there aren't at least 3 elements in your list. One way to handle that could be to return an Option[A] rather than an A. Something like the following:
def third_list[A](ls: List[A]): Option[A] = ls match {
case _ :: _ :: third :: _ =>
Some(third)
case _ =>
None
}
Edit:
Using Option to handle the scenario where the third element isn't present is the ideal approach as it tells the caller of this method that it cannot be guarateed to return a value of A.
If, however, you have to keep the original method signature you could throw an exception in the event that a third element is not present:
def third_list[A](ls: List[A]): A = ls match {
case _ :: _ :: third :: _ =>
third
case _ =>
throw new RuntimeException(s"Error occurred access third element of list. List had length ${ls.length}.")
}
Alternatively could ask the caller of method to provide a default value in the event a third element is no accessible, though in this scenario you are again changing the method signature, and therefore Option is recommended:
def third_list[A](ls: List[A], default: => A): A = ls match {
case _ :: _ :: third :: _ =>
third
case _ =>
default
}
It worth repeating that having the return type be of type Option is still the best practice approach. See this official Scala lang documentation on functional error handling.
Related
I want to do this in Scala:
def sum[T](seq: Seq[T]): T =
seq match {
case last :: Nil => last
case head :: tail => head + sum(tail)
}
But Scala complains that there is a type mismatch on sum(tail): it is expecting a String but got a T - which doesn't sound right of course. I investigated a little, and it looks like Scala's type inference system can only infer that tail is of type Seq[Any]. Is that the issue? What is the correct way to write this in Scala?
The problem is that the compiler doesn't know if method + is available for type T. That business about String is misleading. It just defaults to assuming that + is supposed to be a String concatenation.
If you restrict T to be only some numeric type that can be added together then it will work.
def sum[T:Numeric](seq: Seq[T]): T =
seq match {
case last :: Nil => last
case head :: tail => implicitly[Numeric[T]].plus(head, sum(tail))
}
It can be expressed a little cleaner by adding an import.
def sum[T:Numeric](seq: Seq[T]): T = {
import Numeric.Implicits._
seq match {
case last :: Nil => last
case head :: tail => head + sum(tail)
}
}
Also, :: is intended for List operations. As it is your method will work for a Seq or a List but not, for example, Vector. Change :: to the more generic +: and it will work with many more collection types like Vector, Array, etc.
I have seen this question How to sort a list in Scala by two fields?
This is similar but not a duplicate.
I can easily sort a List[DataPoint] using the answer from the earlier question:
case class DataPoint(keys: List[String], value: Double)
listOfDataPoints.sortBy(point => (point.keys(0), point.keys(1)))
However I don't know the number of items in keys. What I do know is that every DataPoint in a given list will have the same number of keys, so there is never a case of sorting List("a") and List("a", "b").
So how can I sort the list by an unknown number of keys?
What you want to do is
datapoints.sortby(_.keys)
This evidently doesn't work. When we take a look at the signature of sortby, it becomes evident why it doesn't work:
sortBy[B](f: (A) ⇒ B)(implicit ord: math.Ordering[B]): List[A]
Your B is a List[String] and you don't have an instance of Ordering[List[String]]. So what do we do? We supply one!
What we need to do for that is implement the method
def compare(x: T, y: T): Int
We want to compare on the following:
If the first key is different between two items, then use that key for sorting
Otherwise, sort by the rest of the List
If one of the lists is empty, the other one comes first[1]
Our T's here are Strings, but all we need for the T's is to be comparable for this, so we can be a little more general.
def listOrdering[T](implicit ord: Ordering[T]): Ordering[List[T]] = new Ordering[List[T]] {
def compare(x: List[T], y: List[T]): Int = {
(x, y) match {
case (Nil, Nil) => 0 //both empty => equal
case (Nil, _) => -1 //one of the two empty => empty is the smallest
case (_, Nil) => 1 //one of the two empty => empty is the smallest
case (xhead :: xtail, yhead :: ytail) => {
val headdiff = ord.compare(xhead, yhead)
if (headdiff == 0) compare(xtail, ytail) //recursively compare the tails if equivalent
else (headdiff ) //otherwise, the difference in the heads
}
}
}
}
now we can supply the ordering to the sortby method explicitly:
datapoints.sortby(_.keys)(listOrdering)
or provide them in implicit scope
[1]: you indicated this never happens, so any choice is good enough
You could define your own Ordering[List[String]]. For example, you could define:
class ListOrdering[A](implicit aOrd: math.Ordering[A]) extends Ordering[List[A]] {
def compare(a1: List[A], a2: List[A]) = (a1, a2) match {
case (Nil, _) => if (a2.isEmpty) 0 else -1
case (_, Nil) => 1
case (h1 :: t1, h2 :: t2) => if (aOrd.compare(h1, h2) == 0) compare(t1, t2) else aOrd.compare(h1, h2)
}
}
Then making the following available somewhere in scope:
implicit val listOrd = new ListOrdering[String]
you can write:
dps.sortBy(_.keys)
and it should work.
Note that my definition of ListOrdering is generalised to be useable for any type A with an implicit Ordering[A] in scope, and can handle lists of variable length (even though you say that in your case your key lists are always the same length).
Trying to create a method that determines if a set is a subset of another set, both given as parameters. When I tried to test it the console printed out
scala.MatchError : (List(1, 2, 3, 4, 5, 6, 7),List(1, 2, 3, 4)) (of class scala.Tuple2),
the two lists given are what I was using as parameters to test it. Also, scala was making me type out return in front of true and false, any ideas what led to this either?
def subset(a: List[Int], b: List[Int]): Boolean ={
(a,b) match {
case (_,Nil)=> return true
}
b match {
case h::t if (a.contains(h)) => subset(a,t)
case h::t => return false
}}
The other answers don't really answer exactly why your code is incorrect. It appears that you're handling the case when list b is empty and non-empty and that everything should be okay, but in fact you're actually not. Let's look at your code again, with some formatting fixes.
def subset(a: List[Int], b: List[Int]): Boolean = {
(a, b) match {
case (_, Nil) => return true
} // we can never make it past here, because either we return true,
// or a MatchError is raised.
b match {
case h :: t if (a.contains(h)) => subset(a,t)
case h :: t => return false
}
}
The real problem here is that you have two completely disconnected match statements. So when b is non-empty, the first match will fail, because it only handles the case when b is Nil.
As pointed out in the other solutions, the proper way to do this is to merge the two match statements together into one.
def subset(a: List[Int], b: List[Int]): Boolean = {
(a, b) match {
case (_, Nil) => true
case (xs, head :: tail) if(xs contains head) => subset(xs, tail)
case _ => false
}
}
Notice how the return statements are no longer needed. In scala you should avoid using return as much as possible, as it's likely that your way of thinking around return actually lead you into this trap. Methods that return early are likely to lead to bugs, and are difficult to read.
A cleaner way to implement this could use diff. b can be considered a subset of a if the set of elements of b minus the elements of a is empty.
def subset(a: List[Int], b: List[Int]): Boolean = (b.distinct diff a.distinct).nonEmpty
distinct is only required if it's possible for a and b to contain duplicates, because we're trying a List like a Set when it's actually not.
Better yet, if we convert the Lists to Sets, then we can use subsetOf.
def subset(a: List[Int], b: List[Int]): Boolean = b.toSet.subsetOf(a.toSet)
Scala match expression should match to at least one case expression. Otherwise the MatchError is raised.
You should have used the following cases:
(a, b) match {
case (_, Nil) => true
case (aa, h :: t) if aa contains h => subset(aa, t)
case _ => false
}
An alternative way could be to call methods in standard library.
For each element in 'b', check if 'a' contains that element.
Here is the simple code:
def subset(a: List[Int], b: List[Int]): Boolean = {
(b.forall(a.contains(_)))
}
MatchError - This class implements errors which are thrown whenever an object doesn't match any pattern of a pattern matching expression.
Obviously the second list having elements in it will cause this error, as no pattern will match. You should just add another branch to the first match like so:
def subset(a: List[Int], b: List[Int]): Boolean = {
(a, b) match {
case (_, List()) => return true
case _ => b match {
case h :: t if (a.contains(h)) => subset(a, t)
case h :: t => return false
}
}
}
MatchError occurs whenever an object doesn't match any pattern of a pattern matching expression.
An alternative way is by using dropWhile or takeWhile
def subsets(a:List[Int], b:List[Int]):Boolean = {
return b.dropWhile { ele => a.contains(ele)}.size==0
}
OR
def subsets(a:List[Int], b:List[Int]):Boolean = {
return b.takeWhile { ele => a.contains(ele)}.size==b.size
}
I'm learning scala, and this question may be stupid, but... why?
For example, this is ok:
def matchList(ls: List[Int]): List[Int] = ls match {
case 1 :: rest => rest
case a :: b :: rest => (a + b) :: rest
case _ => ls
}
matchList: (ls: List[Int])List[Int]
But function with type parameter does not compile:
def matchList[T](ls: List[T]): List[T] = ls match {
case 1 :: rest => rest
case a :: b :: rest => (a + b) :: rest
case _ => ls
}
<console>:10: error: type mismatch;
found : T
required: String
case a :: b :: rest => (a + b) :: rest
Why?
For any type T the operation T + T doesn't make any sense. (Do all types support +? No. Think of adding two dogs or two employees.)
In your case, the string concatenation operator is getting invoked (added via any2stringadd pimp), whose return type is (obviously) String. Hence the error message.
What you need is a way to specify that type T must support an operation where you combine two values of type T to yield a new value of type T. Scalaz's Semigroup fits the bill perfectly.
The following works:
def matchList[T : Semigroup](ls: List[T]): List[T] = ls match {
case 1 :: rest => rest
case a :: b :: rest => (a |+| b) :: rest // |+| is a generic 'combining' operator
case _ => ls
}
I think the problem lies in (a + b), the only universal usage of the + operator is string concatenation, so a and b must both be Strings (or automatically convertible to Strings) in order for that to be valid. Your parameterized type T isn't known to be a String, so it fails to compile.
In the second example, your a, b variables of declared type T are not convertible to String, which is the required argument type of +, inferred from your program (i.e. the view applied to the type of arguments of +in the absence of any other information).
In the first example, inference can guess the right + function to apply, considering it takes as arguments the type of elements of the list, and that thankfully, you have mentioned in the type declaration that the type of those elements is Int. Try typing
"1"+2
1 + 2
... in an REPL and see what Scala tries to do. Then read about views.
Now, I surmise that by using that type parameter T above, you are trying to write a function that works with any numerical type, aren't you ? In that case, you can work with the Numeric trait. I'll let you read up on implicits before suggesting the following:
def matchList[T](ls: List[T])(implicit n:Numeric[T]): List[T] = {
import n.mkNumericOps
ls match {
case 1 :: rest => rest
case a :: b :: rest => (a + b) :: rest
case _ => ls
}}
You get:
matchList(List(1,2,3))
res2: List[Int] = List(2, 3)
matchList(List(2,3,4))
res4: List[Int] = List(5, 4)
matchList(List(2.0,3.0,4.0))
res5: List[Double] = List(5.0, 4.0)
Without any import:
def matchList[T](ls: List[T])(implicit wrapper:Numeric[T]): List[T] = ls match {
case 1 :: rest => rest
case a :: b :: rest => wrapper.plus(a, b) :: rest
case _ => ls
}
I've had this situation occur a number of times in the library I'm writing, and I'm not particularly satisfied with the solutions I've come up with so far.
Let's say that I have an expensive function f that takes an item of type T and returns a value of type Option[U]. Now, suppose I have a collection of type T and I want to retrieve the first non-None value returned by f when performed across the elements of T without evaluating f for all elements of T if the value has already been found.
The only way I've come up with to do this is to wrap F into an Extractor Object, and use it with scala's collectFirst method.
For example:
object FMatch { def unapply(t : T) = f(t) }
collection.collectFirst{ case FMatch(result) => result }
This seems a little inelegant, and I'm not certain whether f is evaluated only once or twice for each result (I haven't tested this to find out yet). It seems like it would be useful to have a version of collectFirst that takes a parameter of type T => Option[U] instead of a PartialFunction1[T].
Is there a more elegant way to do this that I'm missing?
Use a view over the collection, to make it lazy and defer invocation of that function until the last possible moment (e.g. it won't be called at all for elements beyond the first match):
xs.view map {f(_)} collectFirst {case Some(x) => x}
or
xs.view map {f(_)} find {_.isDefined}
or in the point-free style, as per Alexey's response:
xs.view map {f} find {_.isDefined}
That should hopefully give you a couple of alternative ways to think about the problem more generally :)
Use this:
collection.toIterator.map(f).find(_.isDefined)
#annotation.tailrec
def first[A, B](as: Traversable[A], f: A => Option[B]): Option[B] =
if (as.isEmpty) None
else f(as.head) match {
case s # Some(_) => s
case _ => first(as.tail, f)
}
Give a partial functions to collectFirst
collectionT
.collectFirst { t =>
f(t) match {
case Some(u) => u
}