Pattern match element of list in Scala - list

I am trying to do it as follows:
def contains(x: Int, l: List[Int]) = l match { // this is just l.contains(x)
case _ :: x :: _ => true
case _ => false
}
Unfortunately it does not work
scala> contains(0, List(1, 2, 3))
res21: Boolean = true
scala> contains(1, List(1, 2, 3))
res22: Boolean = true
scala> contains(3, List(1, 2, 3))
res23: Boolean = true
Could you please explain why ?

To match a number equal to x you can put it into backticks:
def contains(x: Int, l: List[Int]) = l match {
case _ :: `x` :: _ => true
case _ => false
}
Unfortunately :: matcher takes exactly one item from list – the first one, so this code would work only to find the second item in l:
scala> contains(1, List(1,2,3))
res2: Boolean = false
scala> contains(2, List(1,2,3))
res3: Boolean = true
scala> contains(3, List(1,2,3))
res4: Boolean = false
I believe, you can't match for an arbitrary item in a list without recursion:
def contains(x: Int, l: List[Int]): Boolean = l match { // this is just l.contains(x)
case `x` :: xs => true
case _ :: xs => contains(x, xs)
case _ => false
}

The first case matches any item in a non empty list, note,
scala> contains(123, List(1, 2, 3))
res1: Boolean = true
scala> contains(123, List())
res2: Boolean = false
A recursive method that matches against the head item of the list may work.

First, x in case section is alias for local variable. It's not x you passed to method.
Second, _ :: x :: _ matches any list with two elements and more. So all your outputs is true.

This might work,
def contains(y: Int, l: List[Int]) = l match { // this is just l.contains(x)
case _ :: x :: _ if(x == y)=> true
case _ => false
}

Your approach does not work, because the x in the pattern match is bound to whatever value the second list element has. It's basically a fresh variable.
Alternative to S.K's answer
def contains(y: Int, l: List[Int]) = l match { // this is just l.contains(x)
case _ :: x :: _ => x == y
case _ => false
}
or you can also write
def contains[A](y: A, l: Seq[Int]) = (l.lift)(1).exists(_ == y)

Related

takeWhile in Scala for element n+1

Define the function dropWhileSmallerThanFive, it should take a list and discard the first n elements, until the next element (n+1) is greater or equal to 5.
*Use one of Scala's built-in list functions (e.g. takeWhile).
I tried this:
def dropWhileSmallerThanFive(xs: List[Int]): List[Int] = xs match {
case Nil => Nil
case head :: b :: tail if b >= 5 => head :: (b::tail).takeWhile(_>=5)
case _ => Nil
}
But it's completly wrong, what should I do?
Welcome to SO! If you are new to Scala, consider the following beginner-friendly resources
Real-time help: gitter.im/scala/scala
Interactive exercises: scala-exercises.org
Tour of Scala: docs.scala-lang.org/tour/tour-of-scala.html
Hello world template: sbt new scala/scala-seed.g8
Online interactive playground: scastie.scala-lang.org
Scala provides List.dropWhile out-of-the-box, or consider the following recursive implementation
def recDropWhile(l: List[Int], predicate: Int => Boolean): List[Int] = {
#scala.annotation.tailrec
def loop(l: List[Int], predicate: Int => Boolean): List[Int] = {
l match {
case Nil => Nil
case head :: tail => if (predicate(head)) loop(tail, predicate) else (head :: tail)
}
}
loop(l, predicate)
}
Both output
val l = List(1,2,3,4,5,6,7,8)
l.dropWhile(_ < 5) // res3: List[Int] = List(5, 6, 7, 8)
recDropWhile(l, _ < 5) // res4: List[Int] = List(5, 6, 7, 8)

Scala check if List contains slice of element of other List

A : List[String]
B : List[String]
I want to know if any element of List B is a slice of any element of list A.
Whats the fastest way to check it?
I think the shortest way is: ListA.exists{ListB.contains}
Fastest for whom? For you or the CPU?
scala> val a = List("abc","def","ghi") ; val b = List("xy", "yz", "ef")
a: List[String] = List(abc, def, ghi)
b: List[String] = List(xy, yz, ef)
scala> b exists (s => a exists (_ contains s))
res0: Boolean = true
scala> val a = List("abc","def","ghi") ; val b = List("xy", "yz")
a: List[String] = List(abc, def, ghi)
b: List[String] = List(xy, yz)
scala> b exists (s => a exists (_ contains s))
res1: Boolean = false

How to fix the pattern-matching exhaustive warning?

Some scala code:
val list = List(Some("aaa"), Some("bbb"), None, ...)
list.filter(_!=None).map {
case Some(x) => x + "!!!"
// I don't want to handle `None` case since they are not possible
// case None
}
When I run it, the compiler complains:
<console>:9: warning: match may not be exhaustive.
It would fail on the following input: None
list.filter(_!=None).map {
^
res0: List[String] = List(aaa!!!, bbb!!!)
How to fix that warning without providing the case None line?
If you are using map after filter, you may to use collect.
list collect { case Some(x) => x + "!!!" }
you can use flatten
scala> val list = List(Some("aaa"), Some("bbb"), None).flatten
list: List[String] = List(aaa, bbb)
scala> list.map {
| x => x + "!!!"
| }
res1: List[String] = List(aaa!!!, bbb!!!)
You could use the #unchecked annotation, although that requires some additional code:
list.filter(_!=None).map { x => ( x : #unchecked) match {
case Some(x) => x + "!!!"
}
}
You can use get method instead of pattern matching.
Here is example code:
scala> val list = List(Some("aaa"), Some("bbb"), None)
list: List[Option[String]] = List(Some(aaa), Some(bbb), None)
scala> list.filter(_ != None).map(_.get + "!!!")
res0: List[String] = List(aaa!!!, bbb!!!)
some other way to solve this issue, without filter and pattern matching
scala> list.flatten map (_ + "!!!")
or
scala> list.flatMap (_ map (_ + "!!!"))

How to extend a Scala list to enable slicing not by explicit position but by given predicate/condition

For
trait Item
case class TypeA(i: Int) extends Item
case class TypeB(i: Int) extends Item
consider a Scala list of items such as
val myList = List(TypeA(1), TypeB(11), TypeB(12),
TypeA(2), TypeB(21),
TypeA(3), TypeB(31))
The goal is to define a new slice method that can be applied onto myList and which takes a predicate or condition as argument; for instance
myList.slice { x => x.isInstanceOf[TypeA] }
would deliver
List(List(TypeA(1), TypeB(11), TypeB(12)),
List(TypeA(2), TypeB(21)),
List(TypeA(3), TypeB(31)))
In this example, an identical result would be achieved by
myList.slice { case TypeA(x) => x < 10 }
Many Thanks.
List already has a slice method - it takes a subset of elements between a start and end index. What you're looking for is repeated application of the span method:
def span(p: (A) ⇒ Boolean): (List[A], List[A])
Which is documented as:
Splits this list into a prefix/suffix pair according to a predicate.
Note: c span p is equivalent to (but possibly more efficient than) (c takeWhile p, c dropWhile p), provided the evaluation of the predicate p does not cause any side-effects.
returns: a pair consisting of the longest prefix of this list whose elements all satisfy p, and the rest of this list.
You can get what you need by repeatedly using this method with an inverse predicate, and an extra bit of logic to ensure that none of the returned Lists are empty.
import annotation.tailrec
def multiSpan[A](xs: List[A])(splitOn: (A) => Boolean): List[List[A]] = {
#tailrec
def loop(xs: List[A], acc: List[List[A]]) : List[List[A]] = xs match {
case Nil => acc
case x :: Nil => List(x) :: acc
case h :: t =>
val (pre,post) = t.span(!splitOn(_))
loop(post, (h :: pre) :: acc)
}
loop(xs, Nil).reverse
}
UPDATE
As requested in comments on the original post, here's a version that enriches list instead of being a standalone method:
implicit class AddMultispanToList[A](val list: List[A]) extends AnyVal {
def multiSpan(splitOn: (A) => Boolean): List[List[A]] = {
#tailrec
def loop(xs: List[A], acc: List[List[A]]) : List[List[A]] = xs match {
case Nil => acc
case x :: Nil => List(x) :: acc
case h :: t =>
val (pre,post) = t.span(!splitOn(_))
loop(post, (h :: pre) :: acc)
}
loop(list, Nil).reverse
}
}
Use as:
myList.multiSpan(_.isInstanceOf[TypeA])
Why couldn't you use partition method from the standard API?
example:
scala> val l = List(3,5,4,6)
l: List[Int] = List(3, 5, 4, 6)
scala>
scala> val (odd,even) = l.partition(_ %2 ==1)
odd: List[Int] = List(3, 5)
even: List[Int] = List(4, 6)
For your example:
scala> val (typeA,typeB) = myList.partition(_.isInstanceOf[TypeA])
typeA: List[Product with Serializable with Item] = List(TypeA(1), TypeA(2), TypeA(3))
typeB: List[Product with Serializable with Item] = List(TypeB(11), TypeB(12), TypeB(21), TypeB(31))
Aren't you looking for filter, which works (almost) without any tweaks for your examples?
$ sbt console
scala> trait Item
scala> case class TypeA(i: Int) extends Item
scala> case class TypeB(i: Int) extends Item
scala> val myList = List(TypeA(1), TypeB(11), TypeB(12),
TypeA(2), TypeB(21),
TypeA(3), TypeB(31))
myList: List[Product with Serializable with Item] = List(TypeA(1), TypeB(11), TypeB(12), TypeA(2), TypeB(21), TypeA(3), TypeB(31))
your first works unaltered:
scala> myList.filter { x => x.isInstanceOf[TypeA] }
res0: List[Product with Serializable with Item] = List(TypeA(1), TypeA(2), TypeA(3))
your second requires a default case:
scala> myList.filter { case TypeA(x) => x < 10; case _ => false }
res2: List[Product with Serializable with Item] = List(TypeA(1(3))
See also collect, which takes a partial function instead of a boolean predicate:
scala> myList.collect { case z # TypeA(x) if x < 10 => z }
res3: List[TypeA] = List(TypeA(1), TypeA(2), TypeA(3))
and can transform as well:
scala> myList.collect { case TypeA(x) if x < 10 => x }
res4: List[Int] = List(1, 2, 3)

filter a list of lists : basic thing

Do you know why this program does not give expected answer (List(3,3)) ?
val l=List(List(1,2),List(3,3))
println(l.filter(_ match{
case u::v => u==v
case _ => false
}))
thanks!
case u::v => u==v
Here, u is of type Int, while v is of type List[Int]. They cannot be equal.
An alternate way of coding this, that would be useful if you might be dealing with lists of arbitrary length and want to filter down to only those lists with all elements the same, would be:
l.filter(ls => !ls.isEmpty && ls.forall(_ == ls.head))
(the !ls.isEmpty fragment presumes you would wish to exclude empty lists)
If you want to extract the first two elements from your sublists and compare them, you need two :: in your case:
l.filter {
case u :: v :: _ => u == v
case _ => false
}
If you want to make sure all elements of the sublists are equal, you could use forall:
l.filter {
case h :: Nil => false // if you want to exclude single elements
case h :: r => r.forall(_ == h)
case _ => false
}
You need to check the documentation of class ::. The constructor argument it takes are (hd: B, tl: List[B])
In your case u becomes hd and v is List[In]. And doing u==v is like doing hd.equals(list) which gives wrong result.
scala> val l= List(List(1,2),List(3,3),List(1),List(1,2,3),List(4,4,4,4))
l: List[List[Int]] = List(List(1, 2), List(3, 3))
scala> l.filter(_ match{
case u::v => Some(u) == v.headOption
case _ => false
})
res8: List[List[Int]] = List(List(3, 3), List(4, 4, 4, 4))
The above is an idiomatic way of doing it.