I am writing equals method for a Scala class where accumUpdates is of Map[Long, Any].
I tried the following:
override def equals(other: Any): Boolean = other match {
case that: DirectTaskResult[_] if (!this.valueBytes.equals(that.valueBytes)) => false
case that: DirectTaskResult[_] if (this.accumUpdates.size != that.accumUpdates.size) => false
case that: DirectTaskResult[_] => {
for ((key, value) <- this.accumUpdates) {
if (!value.equals(that.accumUpdates.get(key))) false
}
}
case _ => false
}
The above gave me:
TaskResult.scala:53: type mismatch;
[error] found : Unit
[error] required: Boolean
[error] for ((key, value) <- this.accumUpdates) {
[error] ^
[error] one error found
Can someone provide hint as to how the Map entries can be iterated ?
Thanks
Try something like:
value.filter(value => value._2.equals(value1.get(value._1))).isEmpty
Reason you get error is, with condition getting satisfied, you will return false, but what if your condition evaluates to true.
Isn't this is you want to do?
case class DirectTaskResult(accumUpdates: Map[Long, Any])
object IterateMap {
val accumUpdates = Map[Long, Any](1L -> "one", 2L -> 2, 3L -> 3)
def thirdCaseClauseOfEquals(that: DirectTaskResult) = {
accumUpdates.keys.forall { key =>
accumUpdates.get(key) == that.accumUpdates.get(key)
}
}
}
It succeeds with this tests:
val t = Map[Long, Any](1L -> "one", 2L -> 2, 3L -> 3)
assert(IterateMap.thirdCaseClauseOfEquals(DirectTaskResult(t)) == true)
assert(IterateMap.thirdCaseClauseOfEquals(DirectTaskResult(t + (4L -> "Four"))) == true)
assert(IterateMap.thirdCaseClauseOfEquals(DirectTaskResult(t - 1L)) == false)
Your iterating over the map values is fine, but your for-loop is not. For-loop always returns Unit. If you want to return something else than Unit, you must use for-yield construct. The other answers showed how to reformulate it - I especially like the solution with forAll which already has a for-loop built in.
Here is illustration of the difference between for and for-yield
scala> def a(mym:Map[_,_]) = {for ((k,v)<-mym) k}
a: (mym: Map[_, _])Unit
scala> def a(mym:Map[_,_]) = {for ((k,v)<-mym) yield k}
a: (mym: Map[_, _])scala.collection.immutable.Iterable[Any]
Related
I'm trying to write a function myfoo which, taken an Int and a list of ints, verifies if the int element is in the list or not. It should return "true" if the int is in the list, false otherwise.
I've written this function, but when I compile it it returns this error:
error: type mismatch;
found : Unit
required: Boolean
breakable { for (i <-l) {
^
one error found*
This is my program:
import scala.util.control.Breaks._
object findEl extends App{
def myfoo (x:Int,l:List[Int]):Boolean={
breakable { for (i <-l) {
i match {
case a if (a==x) => true
case _ => false
break
}
}
}
}
println(myfoo(1,List(1,2,3,4))) //should print "true"
}
How can I solve it? :)
This is how breakable is implemented
def breakable(op: => Unit) {
try {
op
} catch {
case ex: BreakControl =>
if (ex ne breakException) throw ex
}
}
Breakable returns Unit finally. So thats why compiler is complaining.
Here is one way to fix this. Notice I am using var
import scala.util.control.Breaks._
object findEl extends App {
def myfoo(x: Int, l: List[Int]): Boolean = {
var res: Boolean = false
breakable {
for (i <- l) {
i match {
case a if a == x => res = true
break
case _ => ()
}
}
}
res
}
println(myfoo(1, List(1, 2, 3, 4))) //should print "true"
}
Functional way (better way) of implementing the same
def myFoo(num: Int, list: List[Int]): Boolean = list match {
case Nil => false
case `num` :: xs => true
case _ => myFoo(num, list.tail)
}
Below code is same but does not use back ticks
def myFoo(num: Int, list: List[Int]): Boolean = list match {
case Nil => false
case x :: xs if x == num => true
case _ => myFoo(num, list.tail)
}
Scala REPL
scala> def myFoo(num: Int, list: List[Int]): Boolean = list match {
| case Nil => false
| case `num` :: xs => true
| case _ => myFoo(num, list.tail)
| }
myFoo: (num: Int, list: List[Int])Boolean
scala> myFoo(1, List(2, 1, 2))
res0: Boolean = true
Using breakable is not functional practice
Halting the execution of the program using an exception is not functional. Functional programming advocates communicating through interpretation of types. Internally breakable halts the control flow by throwing exception.
Above second way is the way to solve the problem functionally.
you can use this trick instead
def function myFoo(x:Int, xList:List[Int]) = xList.contains(x)
println(myFoo(1, List(1,2,3,4,5,6)))
As an example, we define a function that should convert 1, 3, 42 respectively to "foo", "bar", "qix" and all other integer to "X".
I've come up with 2 implementations :
The method f need to be separate because it can be reuse in other context.
def f(i: Int): Option[String] = i match {
case 1 => Some("foo")
case 3 => Some("bar")
case 42 => Some("qix")
case _ => None
}
def g(i: Int) : String = f(i).getOrElse("X")
And :
def f_ : PartialFunction[Int, String] = {
case 1 => "foo"
case 3 => "bar"
case 42 => "qix"
}
def g_(i: Int) : String = f_.orElse { case _ => "X" }(i)
I tend to prefer the second because it avoid many repetitive Some(…)
WDYT ?
I'm not sure why you want to use option at all when you can just as easily do this and get the exact same result:
def f(i: Int): String = i match {
case 1 => "foo"
case 3 => "bar"
case 42 => "qix"
case _ => "X"
}
It even saves you a pesky getOrElse
You can even go one better and use neither a PartialFunction or a match and just do this:
def f: Int => String = {
case 1 => "foo"
case 3 => "bar"
case 42 => "qix"
case _ => "X"
}
Which saves you writing a disposable i
fScala's Map is already a partial function. So you can use it instead of defining your own function which does exactly what Map does - "A map from keys of type A to values of type B".
So all you have to do is:
val f = Map(1 -> "foo", 3 -> "bar", 42 -> "qix")
def g(i: Int) = f.getOrElse(i, "X")
f(1) //foo
f(4) // throw NoSuchElementException: Key not found: 4
f.get(1) // Some(foo)
f.get(4) // None
g(1) //foo
g(4) //X
Now you can use the function 'g' or reuse 'f' to other needs.
Edited my example according to your comment:
def f(i: Int): Option[String] = {
val map = Map(1 -> "foo", 3 -> "bar", 42 -> "qix")
i match {
case x if (map.contains(x)) => Some(map(x))
case _ => None
}
}
def g(i: Int) : String = f(i).getOrElse("X")
I think the function should react to integers outside the given range in some meaningful way. That's why I would prefer an Option.
Option is a good way to handle null value. Partial function is just a partial matching, they are not same, even though Option and PartialFunction both have similar orElse method
Due to partial function is a function, so it can be chained but option can not, Option is the way to handle null value.
For the partial function you can do like this, it is more like chain of responsibility
def f_1 : PartialFunction[Int, String] = {
case 1 => "1"
}
def f_2 : PartialFunction[Int, String] = {
case 2 => "2"
}
def f_3 : PartialFunction[Int, String] = {
case 3 => "3"
}
f_1.orElse(f_2).orElse(f_3)(3)
You may want to try this. Here HashMap gives you fast lookup:
object SomeMain {
import scala.collection.immutable.HashMap
def f(i: Int): Option[String] = {
HashMap(1 -> "foo", 3 -> "bar", 42 -> "qix").get(i).orElse(None)
}
def g(i: Int): String = f(i).getOrElse("X")
def main(args: Array[String]) {
List(1, 3, 42, 10) foreach { x => println(x + ": " + g(x)) }
}
}
Output:
1: foo
3: bar
42: qix
10: X
I have a list of parameters like List(1,2,3,"abc","c") and a set of functions which validates the data present in the list like isNumberEven, isAValidString etc.
Currently, I take each value of the list and apply proper function which validates the data like isNumberEven(params(0)). This has led to big and messy code which is completely imperative in thinking.
I am expecting that it should be possible to do something like this in Scala -
List(1,2,3,"abc","c").zip(List(fuctions)).foreach{ x => x._2(x._1)}
However, this fails giving a runtime exception of type mismatch:
error: type mismatch;
found : x._1.type (with underlying type Any)
required: Int with String
I tried pattern matching on Function traits but it fails due to type erasure.
Any pointers will be appreciated as how can this be solved.
Very naive and non extensible implementation, I'm not very good with types, surely there's a better way:
val c = List(1,2,3,"abc","c")
def isEven(x: Int) = if(x % 2 == 0) true else false
def isUpperCase(x: String) = if(x.head.isUpper) true else false
c.map {
case x: Int => isEven(x)
case x: String => isUpperCase(x)
case _ => false
}
You could also define list of functions:
scala> val c = List(1,2,3,"abc","c")
c: List[Any] = List(1, 2, 3, abc, c)
scala> def isEven(x: Int) = if(x % 2 == 0) true else false
isEven: (x: Int)Boolean
scala> def isOdd(x: Int) = !isEven(x)
isOdd: (x: Int)Boolean
scala> def isUpperCase(x: String) = if(x.head.isUpper) true else false
isUpperCase: (x: String)Boolean
scala> def someString(x: String) = true
someString: (x: String)Boolean
scala> val ints = List(isEven(_), isOdd(_))
ints: List[Int => Boolean] = List(<function1>, <function1>)
scala> val strings = List(isUpperCase(_), someString(_))
strings: List[String => Boolean] = List(<function1>, <function1>)
scala> c.map {
| case x: Int => ints.map(f => f(x)).exists(f => f(x))
| case x: String => strings.map(f => f(x)).forall(f => f(x))
| case _ => false
| }
res2: List[Boolean] = List(true, true, true, false, false)
I just want to present a different approach without matching, although it is certainly sledgehammer-like.
First all functions are converted to functions of type Any => Boolean.
It iterates over the values in c. For each element it tries to find a function that is applicable and that results in true. If it doesn't find one, false is yielded.
def isEven(i: Int) = i % 2 == 0
def isGreaterThanTwo(i: Int) = i > 2
def hasB(s: String) = s.exists(_ == 'b')
def convert[T](func: T => Boolean) = (a: Any) => func(a.asInstanceOf[T])
val functions = List(isEven _, isGreaterThanTwo _, hasB _)
val c = List(1,2,3,"abc","c")
val result = {
val convertedFunctions = functions.map(convert)
c.map(elem => convertedFunctions.exists(func => Try(func(elem)) getOrElse false))
}
with the result List(false, true, true, true, false).
The upside is that you can have as many functions as you like and it is therefore extensible. The downside is that you rely on exceptions. (which is usually not a good practice)
I first tried a solution with converting to PartialFunction and modifying the isDefined methods so it can be called on Any but then checks for a certain type. Then a lot of type-erasure happened and I couldn't make it work. Maybe that could be worth a shot.
If that is possible the code could be changed to:
def convert[T](func: T => Boolean) = new PartialFunction[Any, Boolean] {
def isDefinedAt(x : Any) = ??? //check if x is an instance of T, type erasure problem
def apply(x : Any) = func(x.asInstanceOf[T])
}
val result = {
val convertedFunctions = functions.map(convert)
c.map(elem => convertedFunctions.exists(func =>
func.isDefinedAt(elem) && func(elem)))
}
which looks pretty nice.
I'm not entirely certain on how you're planning on using the data afterwards, because 'foreach' would not actually return anything. But maybe this pattern-matched solution can help you achieve what you want?
scala> val f1 = (x:Int) => false
f1: Int => Boolean = <function1>
scala> val f2 = (x:String) => true
f2: String => Boolean = <function1>
scala> List(1,2,3,"abc","c").map {
case x:String => f2(x)
case x:Int => f1(x)
}
res3: List[Boolean] = List(false, false, false, true, true)
Say I have a map: Map[Int, String]. How would I get the value [String] with the lowest key [Int]. I've been trying to implement this functionally, but just can't figure out how to do this.
The following code will get you a value with a lowest key (ignoring some corner cases).
def lowestKeyMember[A](m: Map[Int,A]): A = m(m.keys.min)
This will break ties arbitrarily and throw on an empty map. If you need to do this operation frequently and/or on large maps, you should look into SortedMap.
Maps are not normally sorted. You could however use a SortedMap, then the map will be sorted and the first value will be the head. All you need to do is retrieve the head.
map.head()
Come on, people! "Functionally" is code word for "folding".
scala> val m = Map(1->"eins",2->"zwei",3->"drei")
m: scala.collection.immutable.Map[Int,String] = Map(1 -> eins, 2 -> zwei, 3 -> drei)
scala> m.foldLeft(Int.MaxValue -> "") { case (min,p) => if (min._1 <= p._1) min else p }
res0: (Int, String) = (1,eins)
But an 8-char operator?
Let's see, is that enough parens? Don't tell me -> is like - and /: is like /.
scala> (Int.MaxValue -> "" /: m) { case (min,p) => if (min._1 <= p._1) min else p }
<console>:9: error: missing arguments for method /: in trait TraversableOnce;
follow this method with `_' if you want to treat it as a partially applied function
(Int.MaxValue -> "" /: m) { case (min,p) => if (min._1 <= p._1) min else p }
^
Oh, well, OK.
scala> ((Int.MaxValue -> "") /: m) { case (min,p) => if (min._1 <= p._1) min else p }
res2: (Int, String) = (1,eins)
Or,
scala> import math.Ordering.Implicits._
import math.Ordering.Implicits._
scala> ((Int.MaxValue -> "") /: m) { case (min,p) if min <= p => min case (_, p) => p }
res5: (Int, String) = (1,eins)
A variant of the _.keys.min solution that works with Options (i.e. will not throw on an empty map):
scala> val a : Map[Int, String]=Map(1 -> "1", 2 -> "2")
a: Map[Int,String] = Map(1 -> 1, 2 -> 2)
scala> val b : Map[Int, String]=Map()
b: Map[Int,String] = Map()
scala> def valueForMinKey[K,V](a : Map[K,V])(implicit cmp : Ordering[K]) = a.keys.reduceOption(cmp.min(_, _)).map(a(_))
valueForMinKey: [K, V](a: Map[K,V])(implicit cmp: Ordering[K])Option[V]
scala> valueForMinKey(a)
res27: Option[String] = Some(1)
scala> valueForMinKey(b)
res28: Option[String] = None
In this example, the implicit parameter cmp will be satisfied by Ordering.Int. The example will work with any Map where the keys can be ordered (and a matching implict can be found by the compiler).
I have a nested map m which is like:
m = Map("email" -> "a#b.com", "background" -> Map("language" -> "english"))
I have an array arr = Array("background","language")
How do I foldLeft/reduce the array and find the string "english" from the map. I tried this:
arr.foldLeft(m) { (acc,x) => acc.get(x) }
But I get this error:
<console>:10: error: type mismatch;
found : Option[java.lang.Object]
required: scala.collection.immutable.Map[java.lang.String,java.lang.Object]
arr.foldLeft(m) { (acc,x) => acc.get(x) }
You should pay attention to types. Here, you start with m : Map[String, Any] as your acc. You combine with a string x and calls get, which returns an Option[Object]. To continue, you must check that there is a value, check whether this value is a Map, cast (unchecked because of type erasure, hence dangerous).
I believe the fault is in the that the type of your structure, Map[String, Any] represents what you have rather poorly.
Suppose you do instead
sealed trait Tree
case class Node(items: Map[String, Tree]) extends Tree
case class Leaf(s: String) extends Tree
You may add some helpers to make declaring a Tree easy
object Tree {
implicit def fromString(s: String) = Leaf(s)
implicit def fromNamedString(nameAndValue: (String, String))
= (nameAndValue._1, Leaf(nameAndValue._2))
}
object Node {
def apply(items: (String, Tree)*) : Node = Node(Map(items: _*))
}
Then declaring the tree is just as easy as your first version, but the type is much more precise
m = Node("email" -> "a#b.com", "background" -> Node("language" -> "english"))
You can then add methods, for instance in trait Tree
def get(path: String*) : Option[Tree] = {
if (path.isEmpty) Some(this)
else this match {
case Leaf(_) => None
case Node(map) => map.get(path.head).flatMap(_.get(path.tail: _*))
}
}
def getLeaf(path: String*): Option[String]
= get(path: _*).collect{case Leaf(s) =>s}
Or if you would rather do it with a fold
def get(path: String*) = path.foldLeft[Option[Tree]](Some(this)) {
case (Some(Node(map)), p) => map.get(p)
case _ => None
}
Folding as an abstraction over nested maps isn't really supported. Also, you're approaching this in a way that is going to prevent the type system from giving you much help. But, if you insist, then you want a recursive function:
def lookup(m: Map[String,Object], a: Array[String]): Option[String] = {
if (a.length == 0) None
else m.get(a(0)).flatMap(_ match {
case mm: Map[_,_] => lookup(mm.asInstanceOf[Map[String,Object]],a.tail)
case s: String if (a.length==1) => Some(s)
case _ => None
})
}