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 (_ + "!!!"))
Related
This question already has answers here:
Scala flatten a List
(5 answers)
Closed 4 months ago.
how to achieve below result list from the list val l1 = List(1,2,List(3,List(4,5,6),5,6,7)?
result = List(1,2,3,4,5,6,7)
Strangely enough, this actually works in Scala 3, and is kinda-sorta "type-safe":
type NestedList[A] = A match {
case Int => Int | List[NestedList[Int]]
case _ => A | List[NestedList[A]]
}
val input: NestedList[Int] = List(1,2,List(3,List(4,5,6),5,6,7))
def flattenNested[A](nested: NestedList[A]): List[A] =
nested match
case xs: List[NestedList[A]] => xs.flatMap(flattenNested)
case x: A => List(x)
val result: List[Int] = flattenNested(input)
println(result.distinct)
I'd consider this more of a curiosity, though, it feels quite buggy. See also discussion here. As it is now, it would be much preferable to model the input data properly as an enum, so one doesn't end up with a mix of Ints and Lists in the first place.
The following would work,
def flattenOps(l1: List[Any]): List[Int] = l1 match {
case head :: tail => head match {
case ls: List[_] => flattenOps(ls) ::: flattenOps(tail)
case i: Int => i :: flattenOps(tail)
}
case Nil => Nil
}
flattenOps(l1).distinct
Regardless the strange input, I would like to make a common pattern of my items in the list:
import scala.reflec.ClassTag
sealed trait ListItem[A] {
def flattenedItems: List[A]
}
case class SingleItem[A](value: A) extends ListItem[A] {
def flattenedItems: List[A] = value :: Nil
}
case class NestedItems[A](values: List[ListItem[A]]) extends ListItem[A] {
def flattenedItems: List[A] = values.flatMap(_.flattenedItems)
}
// The above would probably take much less lines of code in Scala 3
object ListItem {
def parse[A : ClassTag](value: Any): ListItem[A] = {
value match {
case single: A => SingleItem(single)
case nested: List[Any] => NestedItems(nested.map(parse[A]))
}
}
}
Then given the list as:
val l = List(1, 2, List(3, List(4, 5, 6), 5, 6, 7))
You can parse each value, and then get flattened values using the ListItem's method:
val itemizedList: List[ListItem[Int]] = l.map(ListItem.parse[Int])
val result = itemizedList.flatMap(_.flattenedItems).distinct
I want to get a List[String] from the input. Please help me to find an elegant way.
Desired output:
emp1,emp2
My code:
val ls = List("emp1.id1", "emp2.id2","emp2.id3","emp1.id4")
def myMethod(ls: List[String]): Unit = {
ls.foreach(i => print(i.split('.').head))
}
(myMethod(ls)). //set operation to make it unique ??
If you care about validation, you can consider using Regex:
val ls = List("emp1.id1", "emp2.id2","emp2.id3","emp1.id4","boom")
def myMethod(ls: List[String]) = {
val empIdRegex = "([\\w]+)\\.([\\w]+)".r
val employees = ls collect { case empIdRegex(emp, _) => emp }
employees.distinct
}
println(myMethod(ls))
Outputs:
List(emp1, emp2)
def myMethod(ls: List[String]) =
ls.map(_.takeWhile(_ != '.'))
myMethod(ls).distinct
Since Scala 2.13, you can use List.unfold to do this:
List.unfold(ls) {
case Nil =>
None
case x :: xs =>
Some(x.takeWhile(_ != '.'), xs)
}.distinct
Please not that you want distinct values, therefore you can achieve the same using Set.unfold:
Set.unfold(ls) {
case Nil =>
None
case x :: xs =>
Some(x.takeWhile(_ != '.'), xs)
}
Code run at Scastie.
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)
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)
I'm trying to do some arithmetic on a list that may contain missing values.
So far, I'm representing my list with Option[Int]:
val mylist=List( Option(4), Option(8), None )
With this representation, I can easily apply a function over the list (say, multiply by 2):
scala> mylist.map(_.map(_*2))
res2: List[Option[Int]] = List(Some(8), Some(16), None)
However, this looks more complicated than it needs be, so I'm wondering if I'm missing something.
Also, I can't figure out how to write things like the sum. I guess it should be possible with a (big) reduce expression...
So, I'd like to know if:
List[Option[Int]] is a good representation for this use case
mylist.map(_.map(_*2)) is the best way to map
is there a simple way to do a sum?
Well, it's not a pattern I've used myself, but if values can be "missing" then an Option is appropriate. But a List probably isn't. In a List the position isn't usually something you should be relying on, since it's not random-access. Maybe a Vector would be better, or you need to think of a better way of modelling your problem, i.e. not as a list with missing values.
You can deal with Option nicely using for-expressions:
for (o <- mylist; x <- o) yield x * 2
or flatten the list:
mylist.flatten.map(_ * 2)
To sum it:
mylist.flatten.sum
List[Option[Int]] is a good representation for this use case
Is it possible to flatten it earlier with flatMap? For example, if you are creating this list using map, you could use flatMap instead and not have missing values. My suggestion is to not even represent the missing values if possible. If you need to represent them, Option is ideal.
mylist.map(_.map(_*2)) is the best way to map
is there a simple way to do a sum?
The nested map is probably preferable. You can foldLeft also.
foldLeft is also helpful if you need to do something besides sum/product.
scala> val mylist=List( Option(4), Option(8), None )
mylist: List[Option[Int]] = List(Some(4), Some(8), None)
scala> mylist.foldLeft(0){
| case (acc, Some(i)) => acc + i
| case (acc, _) => acc
| }
res7: Int = 12
scala> (0 /: mylist) {
| case (acc, Some(i)) => acc + i
| case (acc, _) => acc
| }
res8: Int = 12
scala> (0 /: mylist) {
| case (acc, Some(i)) => acc - (i * 2)
| case (acc, _) => acc
| }
res16: Int = -24
So, I'd like to know if:
List[Option[Int]] is a good representation for this use case
Option is definitely the preferable way to express missing values. You could also think about changing it into a List[(Int, Int)] where the first element indicates the position in your original list and the second element represents the value.
mylist.map(_.map(_*2)) is the best way to map
In my opinion there is no shorter or cleaner way to express that. (You have two "levels" that's why you need two maps!) With my suggested data structure this would turn into mylist.map(t => (t._1, t._2*2)).
is there a simple way to do a sum?
No easier way than om-nom-nom suggested. With my data structure it would be mylist.map(_._2).sum
The most general and most concise way to do this is with Scalaz's semigroup type class. That way, you're not restricted to List[Option[Int]] but can apply the same function to List[Int].
import scalaz._
import Scalaz._
object S {
def double[A:Semigroup](l:List[A]) = l.map(x => x |+| x)
def sum[A:Semigroup](l:List[A]) = l.reduce(_ |+| _)
def main(a:Array[String]) {
val l = List(Some(1), None, Some(2))
val l2 = List(1,2)
println(double(l))
println(sum(l))
println(double(l2))
println(sum(l2))
}
}
This prints
List(Some(2), None, Some(4))
Some(3)
List(2, 4)
3
i'm not sure what it is you are trying to achieve, but this does'nt seem like the right approach. if you need to determine if a value exists in your "list", then perhapse a Set would suit your needs better:
scala> val s = Set(4,8)
s: scala.collection.immutable.Set[Int] = Set(4, 8)
scala> s(4)
res0: Boolean = true
scala> s(5)
res1: Boolean = false
scala> s map (_ * 2)
res2: scala.collection.immutable.Set[Int] = Set(8, 16)
scala> s reduceLeft((a,b) => a+b)
res3: Int = 12
or even easier:
scala> s sum
res4: Int = 12
if you need something more sophisticated, and the index of the element in your list is important, you may use a Map where the keys simulate the index, and missing values can be mapped to some default value:
scala> val m = Map(1 -> 4, 2 -> 8) withDefault(n => 0)
m: scala.collection.immutable.Map[Int,Int] = Map(1 -> 4, 2 -> 8)
scala> m(1)
res5: Int = 4
scala> m(3)
res6: Int = 0
scala> m map {case (k,v) => (k,2*v)}
res7: scala.collection.immutable.Map[Int,Int] = Map(1 -> 8, 2 -> 16)
scala> m.foldLeft(0){case (sum,(_,v)) => sum+v}
res8: Int = 12
again, not sure what your needs are, but it feels like you are going the wrong way...
Option is a type i would think twice before using. ask yourself if it's realy necessary. there might be solutions that would achieve what you are trying to do in a more elegant way.