I am trying to convert an array of strings into an array of maps(string,string) by mapping each element into the array to (element,regex it matches). My code is as follows, however it throws me error when I run it.
var articles:Array[Map[String,String]] = rawArticles map(x => x, x match {
case ArticleRE(id) => id
case _ => " "
}
)).toMap
rawArticles is the original array and ArticleRE is the regex I am matching.
It appears to me that your issue is trying to call toMap on something that isn't a Seq[(A, B)]. Assuming a trivial case like this (it compiles just fine in Scala 2.10 with a few changes):
val rawArticles = Array("articleOne", "articleTwo", "articleThree")
val articleRE = "(.*)".r
/* some place holder value for no match */
val noMatch = ""
val articles = rawArticles map { x => Map(
x -> x match {
case articleRE(id) => (id, articleRE.toString)
case _ => ("", noMatch)
})
}
I think your issue here was trying to convert a Seq that wasn't a Seq of Tuples, you can also directly use case in Map, as Map can take a PartialFunction.
If you are sure about the types that you want then this should work:
var articles = rawArticles.map(x => Map(x -> (x match {
case ArticleRE(id) => id
case _ => " "
})))
Related
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'm learning Scala and in the below code using flatMap (taken from 99 Scala problems) I have
def myflatten(somelist : List[Any]): List[Any] = somelist flatMap {
case ms: List[_] => flatten(ms)
case e => List(e)
}
Now Im totally confused what the 'ms' and 'e' are? they must be something key as if I change ms to say dd, I get the error "not found value ms". If I hover over them i get a tool-tip saying 'ms' is a 'List[ ][ ]' and 'e' is 'Any'.
I've tried googling for "Scala List elements ms and e" or "Scala flatMap ms and e" or "Scala what do case ms and case e mean?" but I have not seem to find anything that explains what these 'ms' and 'e' are.
Are they keywords? Where can I find info on them in the Scala documentation?
P.S. I understand the code, but just not what ms and e are
If you're new, let me explain step by step whats going on here.
def myflatten(somelist : List[Any]): List[Any] = somelist flatMap {
case ms: List[_] => flatten(ms)
case e => List(e)
}
Written verbosely:
def myflatten(somelist : List[Any]): List[Any] = somelist flatMap { something =>
something match {
case ms: List[_] => flatten(ms)
case e => List(e)
}
}
What is ms and e?
First let me break this down.
You are flatMapping over a List[Any].
val x = List("Str1", "Str2", "Str3")
val y = x flatMap { elementInList => List(elementInList) }
This means for each element in the list, you are creating a new List with that element in it. Because its a flatMap you essentially get the same (same elements) list back.
Checkout what would happen if you use map instead of flatMap:
val x = List("Str1", "Str2", "Str3")
val y = x map { elementInList => List(elementInList) }
the val y would be:
List(List("Str1"), List("Str2"), List("Str3"))
check out http://www.brunton-spall.co.uk/post/2011/12/02/map-map-and-flatmap-in-scala/
now, looking at the verbose example:
def myflatten(somelist : List[Any]): List[Any] = somelist flatMap { something =>
something match {
case ms: List[_] => flatten(ms)
case e => List(e)
}
}
you are matching on the element in the list or in this case called something.
you are also matching on the elements type.
for example
def myMatch(e: Any): String = {
e match {
case x: String => "Its a String: " + x
case y: Int => "Its a Int: " + y
//notice how im using x twice.. its because they're in separate scope!
case x: Boolean => "Its a Boolean: " + x
case _ => "Its something else!"
}
}
invoke myMatch with the param "hello" and it will return "Its a String: hello".
invoke myMatch with the param 1 and it will return "Its a Int: 1".
check out http://docs.scala-lang.org/tutorials/tour/pattern-matching.html
What is e and ms?
lets look at your code:
def myflatten(somelist : List[Any]): List[Any] = somelist flatMap {
case ms: List[_] => flatten(ms)
case e => List(e)
}
If the element in the list which we are currently looking at is of the type List[_] (the same as List[Any]), we then execute this block, flatten(ms).
ms is the val assigned to the element once matched.
If the element in the list which we are currently looking at is of the type _ or essentially default (case _ =>) then return a List(e) containing one element, which is the element which we were looking at.
This would always return a List[List[Any]]. Which is then flattened to a List[Any].
I hope this helps,
Rhys
Here case ms: List[_] is a typed matching for List type elements. ms is not a keyword, it's just a variable representing element of type List.
And case e is a variable matching, it is kind of catch all scenario. It matches for all elements which are not List (as Lists will be matched by the first case). Again e is also not a keyword.
For more info you can read Kinds of patterns
ms, e - it's only variable names. You can call them as you wish.
In first case:
case ms: List[_] => flatten(ms)
you suppose that content of your list
def myflatten(somelist : List[Any])
can be matched as List[_] of any type
In second case statement:
case e => List(e)
you suppose that content of your list can be anything else.
Read official doc: http://docs.scala-lang.org/tutorials/tour/pattern-matching.html
And here some tutorial: https://kerflyn.wordpress.com/2011/02/14/playing-with-scalas-pattern-matching/
to get some background about scala pattern matching.
In general you are comparing with two different cases (ie) case ms having list of any and the other one is of case default specified by e. so if you have list[_] then will implement flat map or else the second option you specified
In continuation of Scala learning curve
I have two lists of objects. I need to merge these lists into one list, while applying a logic with matching pares.
So, for example, here are the two lists:
case class test(int: Int, str: String)
val obj1 = test(1, "one")
val obj2 = test(2, "two")
val list1 = List(obj1, obj2)
val obj3 = test(2, "Another two")
val obj4 = test(4, "four")
val list2 = List(obj1, obj2)
What I need is:
List(test(1, "one old"), test(2, "Another two updated"), test(4, "four new"))
Of coarse, I can iterate though all elements in an old fashioned way, and do all the conversions there, but that is not the "Scala way" (I guess).
I tried approaching it with foldLeft, but got stuck. Here is what I have that is not working:
list1.foldLeft(list2) { (a:test, b:test) =>
b.int match {
case a.int => {
//Apply logic and create new object
}
}
}
UPDATE
For now I did it in two steps:
var tasks : Seq[ChecklistSchema.Task] = left.tasks.map((task:ChecklistSchema.Task) =>
right.tasks.find(t => t.groupId == task.groupId) match {
case Some(t: ChecklistSchema.Task) => t
case _ => {
task.status match {
case TaskAndValueStatus.Active => task.copy(status = TaskAndValueStatus.Hidden)
case _ => task
}
}
}
)
tasks = tasks ++ right.tasks.filter((t:ChecklistSchema.Task) => !tasks.contains(t))
There is got to be a better approach!
Thanks,
*Assuming val list2 = List(obj3, obj4).
Here's my approach to this:
Apply "old" to all list1 entries
Create a map for list2 in order to efficiently check (in the next method) if a duplicated value came from list2. (breakOut here instructs the compiler to build it using the most appropriate factory. More at https://stackoverflow.com/a/7404582/4402547)
applyLogic decides what to call a not-old test ("new" or "updated")
Put them together, groupBy on the index, applyLogic, and sort (optional).
def merge(left: List[Test], right: List[Test]) = {
val old = list1.map(t => Test(t.int, t.str+" old"))
val l2Map = list2.map(t => (t.int -> t)) (breakOut): Map[Int, Test]
def applyLogic(idx: Int, tests: List[Test]): Test = {
tests.size match {
case 1 => {
val test = tests.head
if(l2Map.contains(test.int)) Test(test.int, test.str + " new") else test
}
case 2 => {
val updated = tests(1)
Test(updated.int, updated.str+" updated")
}
}
}
(old ++ list2).groupBy(t => t.int).map(f => applyLogic(f._1, f._2)).toList.sortBy((t => t.int))
}
val left = List(Test(1, "one"), Test(2, "two"))
val right = List(Test(2, "Another two"), Test(4, "four"))
val result = List(Test(1, "one old"), Test(2, "Another two updated"), Test(4, "four new"))
assert(merge(left, right) == result)
I don't know if this solution is "Scala way" but it is using foldLeft.
case class Test(a: Int, b: String) {
def labeled(label: String) = copy(b = b + " " + label)
}
def merge(left: List[Test], right: List[Test]) = {
val (list, updated) = left.foldLeft((List[Test](), Set[Int]())) { case ((acc, founded), value) =>
right.find(_.a == value.a) match {
case Some(newValue) => (newValue.labeled("updated") :: acc, founded + value.a)
case None => (value.labeled("old") :: acc, founded)
}
}
list.reverse ::: right.filterNot(test => updated(test.a)).map(_.labeled("new"))
}
val left = List(Test(1, "one"), Test(2, "two"))
val right = List(Test(2, "Another two"), Test(4, "four"))
val result = List(Test(1, "one old"), Test(2, "Another two updated"), Test(4, "four new"))
assert(merge(left, right) == result)
(list1 ++ (list2.map(l => l.copy(str = l.str + " new")))).groupBy(_.int).map(
l =>
if (l._2.size >= 2) {
test(l._2(0).int, "Another two updated")
} else l._2(0)
)
map to update new value and use groupBy to update distinct value
I'm a little confused regarding pattern matching on a list in Scala.
For example.
val simplelist: List[Char] = List('a', 'b', 'c', 'd')
//> simplelist : List[Char] = List(a, b, c, d)
def simple_fun(list: List[Char]) = list match {
case (x:Char) :: (y:List[Char]) => println(x)
case _ => Nil
}
//> simple_fun: (list: List[Char])Any
simple_fun(simplelist)
//> a
//| res0: Any = ()
This currently prints only one line of output. Should it not run/pattern match on each element of the List ?
EDIT: I fixed the compile errors and copied the output from the REPL.
Unless you are repeatedly calling simple_fun in some way, what you have there will pattern match the first element and nothing more. To get it to match the whole list, you can get simple_fun to call itself recursively, like this:
val simplelist: List[Char] = List('a', 'b', 'c', 'd')
def simple_fun(list: List[Char]): List[Nothing] = list match {
case x :: xs => {
println(x)
simple_fun(xs)
}
case _ => Nil
}
Note I've also left out some of the types as the Scala compiler can infer them, leaving you with less cluttered, more readable code.
As a small side-note, calling println repeatedly inside the function like that is not particularly functional - as it is all about side effects. A more idiomatic approach would be to have the function construct a string describing the list, which is then output with a single call to println - so the side-effects are kept in a single well-defined place. Something like this would be one approach:
def simple_fun(list: List[Char]):String = list match {
case x :: xs => x.toString + simple_fun(xs)
case Nil => ""
}
println(simple_fun(simple_list))
I would also like to mention that the case for lists can be divided not only the head and tail, as well as any N number of list elements:
def anyFunction(list: List[Int]): Unit =
list match {
// ...methods that have already been shown
case first :: second :: Nil => println(s"List has only 2 elements: $first and $second")
case first :: second :: tail => println(s"First: $first \nSecond: $second \nTail: $tail")
}
Hope it will be useful to someone.
I think the following should work:
def flatten(l: List[_]): List[Any] = l match {
case Nil => Nil
case (head: List[_]) :: tail => flatten(head) ::: flatten(tail)
case head :: tail => head :: flatten(tail)
}
The first line is a match for Nil, so if we don't find anything return nothing.
The second line will identify List of Lists and recall the flatten method and flatten the list of lists.
What is the best way to remove the first occurrence of an object from a list in Scala?
Coming from Java, I'm accustomed to having a List.remove(Object o) method that removes the first occurrence of an element from a list. Now that I'm working in Scala, I would expect the method to return a new immutable List instead of mutating a given list. I might also expect the remove() method to take a predicate instead of an object. Taken together, I would expect to find a method like this:
/**
* Removes the first element of the given list that matches the given
* predicate, if any. To remove a specific object <code>x</code> from
* the list, use <code>(_ == x)</code> as the predicate.
*
* #param toRemove
* a predicate indicating which element to remove
* #return a new list with the selected object removed, or the same
* list if no objects satisfy the given predicate
*/
def removeFirst(toRemove: E => Boolean): List[E]
Of course, I can implement this method myself several different ways, but none of them jump out at me as being obviously the best. I would rather not convert my list to a Java list (or even to a Scala mutable list) and back again, although that would certainly work. I could use List.indexWhere(p: (A) ⇒ Boolean):
def removeFirst[E](list: List[E], toRemove: (E) => Boolean): List[E] = {
val i = list.indexWhere(toRemove)
if (i == -1)
list
else
list.slice(0, i) ++ list.slice(i+1, list.size)
}
However, using indices with linked lists is usually not the most efficient way to go.
I can write a more efficient method like this:
def removeFirst[T](list: List[T], toRemove: (T) => Boolean): List[T] = {
def search(toProcess: List[T], processed: List[T]): List[T] =
toProcess match {
case Nil => list
case head :: tail =>
if (toRemove(head))
processed.reverse ++ tail
else
search(tail, head :: processed)
}
search(list, Nil)
}
Still, that's not exactly succinct. It seems strange that there's not an existing method that would let me do this efficiently and succinctly. So, am I missing something, or is my last solution really as good as it gets?
You can clean up the code a bit with span.
scala> def removeFirst[T](list: List[T])(pred: (T) => Boolean): List[T] = {
| val (before, atAndAfter) = list span (x => !pred(x))
| before ::: atAndAfter.drop(1)
| }
removeFirst: [T](list: List[T])(pred: T => Boolean)List[T]
scala> removeFirst(List(1, 2, 3, 4, 3, 4)) { _ == 3 }
res1: List[Int] = List(1, 2, 4, 3, 4)
The Scala Collections API overview is a great place to learn about some of the lesser known methods.
This is a case where a little bit of mutability goes a long way:
def withoutFirst[A](xs: List[A])(p: A => Boolean) = {
var found = false
xs.filter(x => found || !p(x) || { found=true; false })
}
This is easily generalized to dropping the first n items matching the predicate. (i<1 || { i = i-1; false })
You can also write the filter yourself, though at this point you're almost certainly better off using span since this version will overflow the stack if the list is long:
def withoutFirst[A](xs: List[A])(p: A => Boolean): List[A] = xs match {
case x :: rest => if (p(x)) rest else x :: withoutFirst(rest)(p)
case _ => Nil
}
and anything else is more complicated than span without any clear benefits.