Below code uses case statement to determine which distance function should be applied manhattanDistance or eucleudianDistance
Can this code be generalized further using traits or DRY principle so it is more maintainable ?
object general {
println("Welcome to the Scala worksheet") //> Welcome to the Scala worksheet
object DistanceOptions extends Enumeration {
type Dist = Value
val Manhattan, Eucleudian = Value
}
object DistanceFunctions {
def manhattanDistance(l1: (DataLine, DataLine)): Double = {
val t: List[(Double, Double)] = l1._1.points.zip(l1._2.points)
t.map(m => Math.abs(m._1 - m._2)).sum
}
def eucleudianDistance(l1: (DataLine, DataLine)): Double = {
val ld: List[(Double, Double)] = l1._1.points.zip(l1._2.points)
val sum = ld.map(m => Math.abs(m._1 - m._2) + Math.abs(m._1 - m._2)).sum
Math.sqrt(sum)
}
def getDistance(s: DistanceOptions.Dist, l1: (DataLine, DataLine)) = {
s match {
case DistanceOptions.Manhattan => DistanceFunctions.manhattanDistance(l1)
case DistanceOptions.Eucleudian => DistanceFunctions.eucleudianDistance(l1)
}
DistanceFunctions.manhattanDistance(l1)
DistanceFunctions.eucleudianDistance(l1)
}
}
case class DataLine(label: String, points: List[Double])
val l = (DataLine("a", List(1, 2)), DataLine("b", List(1, 2)))
//> l : (general.DataLine, general.DataLine) = (DataLine(a,List(1.0, 2.0)),Dat
//| aLine(b,List(1.0, 2.0)))
DistanceFunctions.getDistance(DistanceOptions.Manhattan, l)
//> res0: Double = 0.0
DistanceFunctions.getDistance(DistanceOptions.Eucleudian, l)
//> res1: Double = 0.0
}
Updated using type classes :
object gen extends App {
object DistanceOptions extends Enumeration {
type Dist = Value
val Manhattan, Eucleudian = Value
}
trait DistanceFunctionsType[T, A] {
def manhattanDistance(t: (T, T)): A
def eucleudianDistance(t: (T, T)): A
}
object DistanceFunctions extends DistanceFunctionsType[DataLine, Double] {
def manhattanDistance(l1: (DataLine, DataLine)): Double = {
val t: List[(Double, Double)] = l1._1.points.zip(l1._2.points)
t.map(m => Math.abs(m._1 - m._2)).sum
}
def eucleudianDistance(l1: (DataLine, DataLine)): Double = {
val ld: List[(Double, Double)] = l1._1.points.zip(l1._2.points)
val sum = ld.map(m => Math.abs(m._1 - m._2) + Math.abs(m._1 - m._2)).sum
Math.sqrt(sum)
}
def getDistance(distanceOptions: DistanceOptions.Dist, l1: (DataLine, DataLine)) = {
distanceOptions match {
case DistanceOptions.Manhattan => DistanceFunctions.manhattanDistance(l1)
case DistanceOptions.Eucleudian => DistanceFunctions.eucleudianDistance(l1)
}
}
}
case class DataLine(label: String, points: List[Double])
val l = (DataLine("a", List(1, 2)), DataLine("b", List(1, 2)))
println(DistanceFunctions.getDistance(DistanceOptions.Manhattan, l))
println(DistanceFunctions.getDistance(DistanceOptions.Eucleudian, l))
}
In implementing this structure I found this guide helpful : http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html
Yes—see for example Spire's MetricSpace, which would allow you to write something like this:
case class DataLine(points: List[Double])
import spire.algebra._
object manhattanDistance extends MetricSpace[DataLine, Double] {
def distance(v: DataLine, w: DataLine): Double = {
val ld: List[(Double, Double)] = v.points.zip(w.points)
val sum = ld.map(m =>
math.abs(m._1 - m._2) + math.abs(m._1 - m._2)
).sum
math.sqrt(sum)
}
}
This approach allows you to avoid the enumeration, and if you use Spire's implementation you get nice operators, a clean way to test that your implementation satisfies e.g. the triangle inequality, and the benefit of a lot of smart people having thought about performance, specialization, etc. for you.
Related
Say I have a method like this:
def getClassFromIterable(iterable: Iterable[Any]): Class[_] = {
iterable.head.getClass
}
This will get the class of the top of the list, but will fail if the list is empty.
How can I get the class of a passed list that has zero or more elements?
Supplementing Luis' answer with a reflective solution, consider
import scala.reflect.runtime.universe._
def toTable[A <: Product](ps: List[A])(implicit ev: TypeTag[A]) = {
val separator = "\t\t"
ps match {
case Nil =>
val header = typeOf[A].members.collect { case m: MethodSymbol if m.isCaseAccessor => m.name }.toList
header.mkString("", separator , "\n")
case head :: _ =>
val header = head.productElementNames.toList
val rows = ps.map(_.productIterator.mkString(separator))
header.mkString("", separator, "\n") + rows.mkString("\n")
}
}
which outputs
case class Point(x: Double, y: Double)
println(toTable(List(Point(1,2), Point(3,4))))
x y
1.0 2.0
3.0 4.0
Based on Get field names list from case class
For this kind of problems, please consider using a typeclass instead.
import scala.collection.immutable.ArraySeq
trait TableEncoder[T] {
def header: ArraySeq[String]
def asRow(t: T): ArraySeq[String]
}
object TableEncoder {
def toTable[T](data: IterableOnce[T])
(implicit encoder: TableEncoder[T]): ArraySeq[ArraySeq[String]] = {
val builder = ArraySeq.newBuilder[ArraySeq[String]]
builder.addOne(encoder.header)
builder.addAll(data.iterator.map(encoder.asRow))
builder.result()
}
}
Which you can use like this:
final case class Point(x: Int, y: Int)
object Point {
final implicit val PointTableEncoder: TableEncoder[Point] =
new TableEncoder[Point] {
override val header: ArraySeq[String] =
ArraySeq("x", "y")
override def asRow(point: Point): ArraySeq[String] =
ArraySeq(
point.x.toString,
point.y.toString
)
}
}
TableEncoder.toTable(List(Point(1, 2), Point(3, 3)))
// res: ArraySeq[ArraySeq[String]] = ArraySeq(
// ArraySeq("x", "y"),
// ArraySeq("1", "2"),
// ArraySeq("3", "3")
// )
How to make this code work?
sealed abstract class Addable[A] {
def sum(el: Seq[A]): A
}
class MyAddable[A]() extends Addable[A] {
override def sum(el: Seq[A]): A = {
el.sum
}
}
val myvec = Vector(1, 2, 3)
val mylist = List(1, 2, 3)
val inst = new MyAddable
val res0 = inst.sum(mylist) // should return 6
val res1 = inst.sum(myvec) // should return 6
println(s"res0 = $res0")
println(s"res1 = $res1")
I want to pass a generic data type (Vector/List[Int]) and get a sum of it's elements using the described signatures and code structure.
At the moment I am getting:
found : immutable.this.List[scala.this.Int]
required: Seq[scala.this.Nothing]
Scalafiddle
The specific error is here:
val inst = new MyAddable
which should be
val inst = new MyAddable[Int]()
MyAddable is generic but you are not specifying a type, so it is assuming Nothing, hence the error message.
sealed abstract class Addable[A] {
def sum(el: Seq[A]): A
}
class MyAddable[A: Numeric]() extends Addable[A] {
override def sum(el: Seq[A]): A = {
el.sum
}
}
val myvec = Vector(1, 2, 3)
val mylist = List(1, 2, 3)
val inst = new MyAddable[Int]()
val res0 = inst.sum(mylist)
val res1 = inst.sum(myvec)
println(s"res0 = $res0")
println(s"res1 = $res1")
import cats.{Semigroup}
import cats.implicits._
// Specify a generic Reduce Function. Use Contravariant parameter to support reduce on derived types
trait Reduce[-F[_]] {
def reduce[A](fa:F[A])(f:(A,A) => A):A
}
object Reduce {
implicit val SeqReduce = new Reduce[Seq] {
def reduce[A] (data:Seq[A])(f:(A,A) => A ):A = data reduce f
}
implicit val OptReduce = new Reduce[Option] {
def reduce[A] (data:Option[A])(f:(A,A) => A ):A = data reduce f
}
}
// Generic sum function
def sum[A:Semigroup, F[_]](container: F[A])(implicit red:Reduce[F]):A = {
red.reduce(container)(Semigroup.combine(_,_))
}
val myvec = Vector(1, 2, 3)
val mylist = List (1, 2, 3)
val mymap = Map ( 1 -> "one",
2 -> "two",
3 -> "three"
)
val myopt = Some(1)
val res0 = sum(myvec)
val res1 = sum(mylist)
val res2 = sum(myopt)
println(s"res0 = $res0")
println(s"res1 = $res1")
println(s"res2 = $res2")
This gets a little more complicated for Maps
The following code is producing run time error as below. Could reason why the following error. Please explain.
Exception in thread "main" scala.MatchError: Some(Some(List(17))) (of class scala.Some)
at com.discrete.CountingSupp$.$anonfun$tuplesWithRestrictions1$1(CountingSupp.scala:43)
def tuplesWithRestrictions1(): (Int, Map[Int, Option[List[Int]]]) = {
val df = new DecimalFormat("#")
df.setMaximumFractionDigits(0)
val result = ((0 until 1000) foldLeft[(Int, Map[Int, Option[List[Int]]])] ((0, Map.empty[Int, Option[List[Int]]]))) {
(r: (Int, Map[Int, Option[List[Int]]]), x: Int) => {
val str = df.format(x).toCharArray
if (str.contains('7')) {
import scala.math._
val v = floor(log10(x)) - 1
val v1 = (pow(10, v)).toInt
val m: Map[Int, Option[List[Int]]] = (r._2).get(v1) match {
case None => r._2 + (v1 -> Some(List(x)))
case Some(xs: List[Int]) => r._2 updated(x, Some(x::xs))
}
val f = (r._1 + 1, m)
f
} else r
}
}
result
}
Return type of .get on map is
get(k: K): Option[V]
Scala doc
/** Optionally returns the value associated with a key.
*
* #param key the key value
* #return an option value containing the value associated with `key` in this map,
* or `None` if none exists.
*/
def get(key: K): Option[V]
Now,
r._2.get(v1) returns an option of Value. So the final return type would be Option[Option[List[Int]]].
You are trying to pattern match for Option[T] but the real value type is Option[Option[Int]] which is not captured in the match.
Use r._2(v1) to extract the value and match. Throws exception when v1 is not found in map.
Match inside map providing default value.
r._2.get(k1).map {
case None => r._2 + (v1 -> Some(List(x)))
case Some(value) => r._2 updated(x, Some(x::xs))
}.getOrElse(defaultValue)
def tuplesWithRestrictions1(): (Int, Map[Int, List[Int]]) = {
val df = new DecimalFormat("#")
df.setMaximumFractionDigits(0)
val result = ((0 until 1000) foldLeft[(Int, Map[Int, List[Int]])] ((0, Map.empty[Int, List[Int]]))) {
(r: (Int, Map[Int, List[Int]]), x: Int) => {
val str = df.format(x).toCharArray
if (str.contains('7')) {
import scala.math._
val v = floor(log10(x))
val v1 = (pow(10, v)).toInt
val m: Map[Int, List[Int]] = (r._2).get(v1) match {
case Some(xs: List[Int]) => r._2 updated(v1, x :: xs)
case None => r._2 + (v1 -> List(x))
}
val f = (r._1 + 1, m)
f
} else r
}
}
result
}
In the following Scala code I have a sequence of currying functions with different signatures. I want to iterate through them and invoke.
def intCheck(b: Int)(a: Int) = a == b
def stringCheck(b: String)(a: String) = a == b
def doubleCheck(b: Double)(a: Double) = a == b
val list = Seq(intCheck(1) _, stringCheck("a") _, doubleCheck(2.3) _)
for (f <- list) {
//if f is 1st function
f(2) // LINE 1
//if f is 2nd function
f("a") // LINE 2
//if f is 3rd function
f(2.0) // LINE 3
}
But for the LINE 1,2 & 3 I get a compilation error "Type mismatch, expected: String with Int with Double, actual: Int". How can I enforce compiler to avoid type-check here if I am sure about the type here.
i think this is a way...
sealed abstract class AnyChecker(val a:Any,val b:Any) {
def eval = a==b
}
class IntChecker(override val a:Int,override val b:Int) extends AnyChecker(a,b)
class DoubleChecker(override val a:Double,override val b:Double) extends AnyChecker(a,b)
class StringChecker(override val a:String,override val b:String) extends AnyChecker(a,b)
object IntChecker {
def apply(a:Int,b:Int) = new IntChecker(a,b)
def unapply(intChecker: IntChecker) = Some(intChecker.a,intChecker.b)
}
object DoubleChecker {
def apply(a:Double,b:Double) = new DoubleChecker(a,b)
def unapply(doubleChecker: DoubleChecker) = Some(doubleChecker.a,doubleChecker.b)
}
object StringChecker {
def apply(a:String,b:String) = new StringChecker(a,b)
def unapply(stringChecker: StringChecker) = Some(stringChecker.a,stringChecker.b)
}
val list = List(IntChecker(1,3), StringChecker("a","a"), DoubleChecker(2.3,3.1), StringChecker("a","b"), StringChecker("a","c"), StringChecker("x","x"))
for (f <- list) {
f match {
case a:IntChecker => println(s"a:${a.a}, b:${a.b}, ${a.eval}")
case a:DoubleChecker => println(s"a:${a.a}, b:${a.b}, ${a.eval}")
case StringChecker("a","a") => println("equals")
case StringChecker("a","b") => println("not equals")
case StringChecker("a",b) => println( StringChecker("a",b).eval)
case StringChecker(a,b) => println(StringChecker(a,b).eval)
}
}
Please, check this, i am sure this will help you.
http://bplawler.tumblr.com/post/7493366722/scala-programming-unapply-and-case-classes
Also, another simple way is only using AnyChcker....
class AnyChecker[T](val a: T, val b: T) {
def eval = a == b
override def toString = s"Checker($a,$b)"
}
object AnyChecker {
def apply[T](a: T, b: T) = new AnyChecker(a, b)
def unapply[T](doubleChecker: AnyChecker[T]) = Some(doubleChecker.a, doubleChecker.b)
}
val list2 = List(AnyChecker(1, 3), AnyChecker("a", "a"), AnyChecker(2.3, 3.1), AnyChecker("a", "b"), AnyChecker("a", "c"), AnyChecker("x", "x"))
for (checker <- list2) {
checker match {
case AnyChecker(1, 3) => println("ints")
case AnyChecker(2.3, 3.1) => println("doubles")
case AnyChecker("a","a") => println("double a")
case checker1: AnyChecker[Any] =>println(checker1)
}
}
if you only write like a tupes....
val list3 = List((1, "1"), ("a", "a"), (2.3, 3.1), ("a", "b"), ("a", "c"), ("x", "x")).map(element=>AnyChecker(element._1,element._2))
for (checker <- list3) {
checker match {
case AnyChecker(1, 3) => println("ints")
case AnyChecker(2.3, 3.1) => println("doubles")
case AnyChecker("a","a") => println("double a")
case checker1: AnyChecker[Any] =>println(checker1.eval)
}
}
I want to write some mergesort function.
How to supply Ordering[T] to merge subfunction?
The overall structure of application is the following:
object Main extends App {
...
val array: Array[Int] = string.split(' ').map(_.toInt)
def mergesort[T](seq: IndexedSeq[T]): IndexedSeq[T] = {
def mergesortWithIndexes(seq: IndexedSeq[T],
startIdx: Int, endIdx: Int): IndexedSeq[T] = {
import Helpers.append
val seqLength = endIdx - startIdx
val splitLength = seq.length / 2
val (xs, ys) = seq.splitAt(splitLength)
val sortXs = mergesortWithIndexes(xs, startIdx, startIdx + seqLength)
val sortYs = mergesortWithIndexes(ys, startIdx + seqLength, endIdx)
def merge(sortXs: IndexedSeq[T], sortYs: IndexedSeq[T],
writeFun: Iterable[CharSequence] => Path)(ord: math.Ordering[T]): IndexedSeq[T] = {
...
while (firstIndex < firstLength || secondIndex < secondLength) {
if (firstIndex == firstLength)
buffer ++ sortYs
else if (secondIndex == secondLength)
buffer ++ sortXs
else {
if (ord.lteq(minFirst, minSecond)) {
...
} else {
...
}
}
}
buffer.toIndexedSeq
}
merge(sortXs, sortYs, append(output))
}
mergesortWithIndexes(seq, 0, seq.length)
}
val outSeq = mergesort(array)
Helpers.write(output)(Vector(outSeq.mkString(" ")))
}
I want to have general merge() function definition, but in application I use IndexedSeq[Int] and thus expecting pass predefined Ordering[Int].
Adding implicit Ordering[T] parameter to the outermost function should fix the problem, and passing non Ordering[T] arguments will result in compile error.
Scala's sort functions do the same thing: https://github.com/scala/scala/blob/2.12.x/src/library/scala/collection/SeqLike.scala#L635
def mergesort[T](seq: IndexedSeq[T])(implicit ord: math.Ordering[T]): IndexedSeq[T] = {