Reputation: 257
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
}}
Upvotes: 0
Views: 470
Reputation: 1578
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
}
Upvotes: 0
Reputation: 55569
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 List
s to Set
s, then we can use subsetOf
.
def subset(a: List[Int], b: List[Int]): Boolean = b.toSet.subsetOf(a.toSet)
Upvotes: 5
Reputation: 2146
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(_)))
}
Upvotes: 1
Reputation: 1334
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
}
Upvotes: 1
Reputation: 1849
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
}
}
}
Upvotes: 0