I have two sorted lists, and want to create an iterator which will merge the two lists in sorted oder. I'm new to Scala and especially new with writing generic classes. I get a compile error that I'm unable to figure out.
Here is the code for MergingIterator
class MergingIterator[ElementType <: Ordered[ElementType]] (iterator1: BufferedIterator[ElementType], iterator2: BufferedIterator[ElementType]) extends Iterator[ElementType]{
override def hasNext: Boolean = {
iterator1.hasNext || iterator2.hasNext
}
override def next(): ElementType = {
if(!iterator1.hasNext && !iterator2.hasNext){
throw new IllegalStateException("All iterators empty. No next element")
}
val e1 : Option[ElementType] = if(iterator1.hasNext) Some(iterator1.head) else None
val e2 : Option[ElementType] = if(iterator2.hasNext) Some(iterator2.head) else None
if(e1.isDefined && e2.isDefined){
val e1a = e1.get
val e2a = e2.get
if(e1a.equals(e2a) || e1a < e2a){
iterator1.next()
}
else {
iterator2.next()
}
}
else if (e1.isDefined){
iterator1.next
}
else if (e2.isDefined){
iterator2.next()
}
else{
throw new Exception("InvalidState. No elements present")
}
}
}
And here is the Unit Test, which is what doesn't compile:
class MergingIteratorTest extends AnyFunSuite {
test("Both Iterators Empty"){
runTest(List(), List(), List())
}
private def runTest(vals1 : List[ComparableInt], vals2: List[ComparableInt], expected: List[ComparableInt]): Unit ={
val it1 = vals1.iterator.buffered
val it2 = vals2.iterator.buffered
val merging = new MergingIterator[ComparableInt](it1, it2)
val merged = merging.toList
assert(expected.equals(merged))
}
case class ComparableInt(value: Int) extends Ordered[Int] {
override def compare(that: Int): Int = value - that
}
}
However when I try to compile, I get the following errors.
Error:(14, 9) type arguments [MergingIteratorTest.this.ComparableInt] do not conform to class MergingIterator's type parameter bounds [ElementType <: Ordered[ElementType]]
val merging = new MergingIterator[ComparableInt](it1, it2)
Error:(14, 23) type arguments [MergingIteratorTest.this.ComparableInt] do not conform to class MergingIterator's type parameter bounds [ElementType <: Ordered[ElementType]]
val merging = new MergingIterator[ComparableInt](it1, it2)
I'm sure it's something stupid that I'm doing wrong, but due to my lack of experience with scala I've been able to figure out what the problem is. Any help here would be appreciated.
You need to make
case class ComparableInt(value: Int) extends Ordered[ComparableInt] {
override def compare(that: ComparableInt): Int = value.value - value.value
}
The issue is in [ElementType <: Ordered[ElementType]] type bounds - you see ElementType should be ordered to itself and your case ComparableInt implements Ordered[Int] and meaning ComparableInt is not Ordered to itself as MergingIterator signature expects.
Same thing with the Ordering type class.
class MergedIterator[ElmTyp:Ordering](itrA: Iterator[ElmTyp]
,itrB: Iterator[ElmTyp]
) extends Iterator[ElmTyp] {
import Ordering.Implicits._
private val itr1 = itrA.buffered
private val itr2 = itrB.buffered
override def hasNext: Boolean = itr1.hasNext || itr2.hasNext
override def next(): ElmTyp =
if (!itr1.hasNext) itr2.next()
else if (!itr2.hasNext) itr1.next()
else if (itr1.head > itr2.head) itr2.next()
else itr1.next()
}
Related
I have an array of Any (in real life, it's a Spark Row, but it's sufficient to isolate the problem)
object Row {
val buffer : Array[Any] = Array(42, 21, true)
}
And I want to apply some operations on its elements.
So, I've defined a simple ADT to define a compute operation on a type A
trait Op[A] {
def cast(a: Any) : A = a.asInstanceOf[A]
def compute(a: A) : A
}
case object Count extends Op[Int] {
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op[Boolean] {
override def compute(a: Boolean): Boolean = a
}
Given that I have a list of all operations and I know which operation is to apply to each element, let's use these operations.
object GenericsOp {
import Row._
val ops = Seq(Count, Exist)
def compute() = {
buffer(0) = ops(0).compute(ops(0).cast(buffer(0)))
buffer(1) = ops(0).compute(ops(0).cast(buffer(1)))
buffer(2) = ops(1).compute(ops(1).cast(buffer(2)))
}
}
By design, for a given op, types are aligned between cast and combine. But unfortunately the following code does not compile. The error is
Type mismatch, expected: _$1, actual: AnyVal
Is there a way to make it work ?
I've found a workaround by using abstract type member instead of type parameter.
object AbstractOp extends App {
import Row._
trait Op {
type A
def compute(a: A) : A
}
case object Count extends Op {
type A = Int
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op {
type A = Boolean
override def compute(a: Boolean): Boolean = a
}
val ops = Seq(Count, Exist)
def compute() = {
val op0 = ops(0)
val op1 = ops(1)
buffer(0) = ops(0).compute(buffer(0).asInstanceOf[op0.A])
buffer(1) = ops(0).compute(buffer(1).asInstanceOf[op0.A])
buffer(2) = ops(1).compute(buffer(2).asInstanceOf[op1.A])
}
}
Is there a better way ?
It seems that your code can be simplified by making Op[A] extend Any => A:
trait Op[A] extends (Any => A) {
def cast(a: Any) : A = a.asInstanceOf[A]
def compute(a: A) : A
def apply(a: Any): A = compute(cast(a))
}
case object Count extends Op[Int] {
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op[Boolean] {
override def compute(a: Boolean): Boolean = a
}
object AbstractOp {
val buffer: Array[Any] = Array(42, 21, true)
val ops: Array[Op[_]] = Array(Count, Count, Exist)
def main(args: Array[String]): Unit = {
for (i <- 0 until buffer.size) {
buffer(i) = ops(i)(buffer(i))
}
println(buffer.mkString("[", ",", "]"))
}
}
Since it's asInstanceOf everywhere anyway, it does not make the code any less safe than what you had previously.
Update
If you cannot change the Op interface, then invoking cast and compute is a bit more cumbersome, but still possible:
trait Op[A] {
def cast(a: Any) : A = a.asInstanceOf[A]
def compute(a: A) : A
}
case object Count extends Op[Int] {
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op[Boolean] {
override def compute(a: Boolean): Boolean = a
}
object AbstractOp {
val buffer: Array[Any] = Array(42, 21, true)
val ops: Array[Op[_]] = Array(Count, Count, Exist)
def main(args: Array[String]): Unit = {
for (i <- 0 until buffer.size) {
buffer(i) = ops(i) match {
case op: Op[t] => op.compute(op.cast(buffer(i)))
}
}
println(buffer.mkString("[", ",", "]"))
}
}
Note the ops(i) match { case op: Opt[t] => ... } part with a type-parameter in the pattern: this allows us to make sure that cast returns a t that is accepted by compute.
As a more general solution than Andrey Tyukin's, you can define the method outside Op, so it works even if Op can't be modified:
def apply[A](op: Op[A], x: Any) = op.compute(op.cast(x))
buffer(0) = apply(ops(0), buffer(0))
sorry if the title is not very explicative, but I don't know how to explain it. I'm a scala newbie and I'm struggling in finding a solution to my problem. Here's the snippet:
sealed trait Base[T, M] {
var value: Option[T] = None
def initialize(v: T): this.type = {
value = Some(v)
this
}
def combine[K <: M](other: K): M
}
class Child1 extends Base[String, Child1] {
override def combine[K <: Child1](other: K) = {
val c = new Child1()
c.initialize(value.get + " - " + other.value.get)
c
}
}
class Child2 extends Base[Long, Child2] {
override def combine[K <: Child2](other: K) = {
val c = new Child2()
c.initialize(value.get + other.value.get)
c
}
}
object Main extends App {
val c1a = new Child1()
c1a.initialize("a")
val c1b = new Child1()
c1b.initialize("b")
val c21 = new Child2()
c21.initialize(1)
val c22 = new Child2()
c22.initialize(2)
val m1 = Map("child1" -> c1a, "child2" -> c21)
val m2 = Map("child1" -> c1b, "child2" -> c22)
m1("child1").combine(m2("child1"))
}
What I want to achieve is that each subclass of Base can be combined only with objects of the same type.
The compiler complains when calling the combine method due to a mismatch in the type of the argument. Is this a correct approach? Or the structure of the classes for my purpose is to be rewritten?
EDIT
This should be ok as well:
sealed trait Base[T, M] {
var value: Option[T] = None
def initialize(v: T): this.type = {
value = Some(v)
this
}
def combine(other: M): M
}
class Child1 extends Base[String, Child1] {
override def combine(other: Child1) = {
val c = new Child1()
c.initialize(value.get + " - " + other.value.get)
c
}
}
class Child2 extends Base[Long, Child2] {
override def combine(other: Child2) = {
val c = new Child2()
c.initialize(value.get + other.value.get)
c
}
}
CURRENT SOLUTION
The solution I found so far:
val combined = (m1("child1"), m2("child1")) match {
case (a: Child1, b: Child1) => a.combine(b)
case _ => throw new Error("Error")
}
What I want to achieve is that each subclass of Base can be combined
only with objects of the same type.
Instead of using pattern match on (m1("child1"), m2("child1")) you can directly use type check on combine method on each child class. In addition, your code seem more imperative style, such as using var, I have refractored your code in more functional way.
sealed trait Base[T] {
val value: Option[T] = None
def combine[Other](other: Base[Other]): Base[T]
}
case class Child1(override val value: Option[String]) extends Base[String] {
override def combine[Other](other: Base[Other]) = {
other match {
case v: Child1 => this.copy(v.value)
case _ => throw new Error("Error")
}
}
}
case class Child2(override val value: Option[String]) extends Base[String] {
override def combine[Other](other: Base[Other]) = {
other match {
case v: Child2 => this.copy(v.value)
case _ => throw new Error("Error")
}
}
}
val child1 = Child1(Some("child1"))
val child2 = Child2(Some("child2"))
child1.combine(child2) //Will fail
val anotherChild1 = Child1(Some("Another child1"))
child1.combine(anotherChild1) //Will succeed.
Do i have a misunderstanding how implciits work in Scala - given the following trait in Scala,
trait hasConfig {
implicit def string2array(s: java.lang.String): Array[String] = {
LoadedProperties.getList(s)
}
implicit def string2boolean(s: java.lang.String) : java.lang.Boolean = {
s.toLowerCase() match {
case "true" => true
case "false" => false
}
}
var config: Properties = new Properties()
def getConfigs : Properties = config
def loadConfigs(prop:Properties) : Properties = {
config = prop
config
}
def getConfigAs[T](key:String):T = {
if (hasConfig(key)) {
val value : T = config.getProperty(key).asInstanceOf[T]
value
}
else throw new Exception("Key not found in config")
}
def hasConfig(key: String): Boolean = {
config.containsKey(k)
}
}
Though java.util.properties contains (String, String) key value pairs, I expect the following code to work due to the implicit converstion defined,
class hasConfigTest extends FunSuite {
val recModel = new Object with hasConfig
//val prop = LoadedProperties.fromFile("test") Read properties from some file
recModel.loadConfigs(prop)
test("test string paramater") {
assert(recModel.getConfigAs[String]("application.id").equals("framework"))
}
test("test boolean paramater") {
assert(recModel.getConfigAs[Boolean]("framework.booleanvalue") == true)
//Property file contains framework.booleanvalue=true
//expected to return java.lang.boolean, get java.lang.string
}
}
However, I get the following error,
java.lang.String cannot be cast to java.lang.Boolean
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Boolean
Why is the implcit conversion not taking care of this?
It doesn't work because casting (asInstanceOf) is something entirely different than implicit conversions. There are multiple ways in which you can solve this.
Implicit conversion
If you want to use the hardcore implicit conversions magic you should rewrite you getConfigAs method like this:
def getConfig(key:String): String = {
if (hasConfig(key)) {
val value: String = config.getProperty(key)
value
}
else throw new Exception("Key not found in config")
}
You will have to import the conversions into the current scope when you use getConfig.
val recModel = new Object with hasConfig
import recModel._
recModel.loadConfigs(prop)
val value: Boolean = recModel.getConfig("framework.booleanvalue")
Implicit parameters
A better way would be to keep your current API, but then you will have to introduce an implicit parameter because the implementation of getConfigAs needs access to the conversion.
def getConfigAs[T](key:String)(implicit conv: String => T): T = {
if (hasConfig(key)) {
val value: String = config.getProperty(key)
value
}
else throw new Exception("Key not found in config")
}
You will still need to import the necessary conversions at the use site though.
val recModel = new Object with hasConfig
import recModel._
recModel.loadConfigs(prop)
val value = recModel.getConfigAs[Boolean]("framework.booleanvalue")
Typeclasses
A way to avoid having to import your conversions (and possibly implicitly converting all kinds of Strings by accident) is to introduce a new type to encode your conversions. Then you can implement the conversions in its companion object, where implicit search can find them without importing them.
trait Converter[To]{
def convert(s: String): To
}
object Converter {
implicit val string2array: Converter[Array[String]] = new Converter[Array[String]] {
def convert(s: String): Array[String] =
LoadedProperties.getList(s)
}
implicit val string2boolean: Converter[Boolean] = new Converter[Boolean] {
def convert(s: String): Boolean =
s.toLowerCase() match {
case "true" => true
case "false" => false
}
}
}
Then you can change your getConfigAs method.
def getConfigAs[T](key:String)(implicit conv: Converter[T]): T = {
if (hasConfig(key)) {
val value: String = config.getProperty(key)
conv.convert(value)
}
else throw new Exception("Key not found in config")
}
And use it.
val recModel = new Object with hasConfig
recModel.loadConfigs(prop)
val value = recModel.getConfigAs[Boolean]("framework.booleanvalue")
You might also want to take a look over here.
Implicit conversions should be defined in scope, for example in enclosing object or imported into the current scope. In your case they should be defined in scope of the hasConfigTest class.
http://docs.scala-lang.org/tutorials/FAQ/finding-implicits
Here's a simple reproducible example:
object m {
implicit def string2boolean(s: String): Boolean = {
s.toLowerCase() match {
case "true" => true
case "false" => false
}
} //> string2boolean: (s: String)Boolean
println(false || "true") //> true
println(false || "false") //> false
}
I think what you are trying to say, is something like this:
import java.util.Properties
object LoadedProperties {
def getList(s: String): Array[String] = Array.empty
}
object hasConfig {
sealed trait ConfigReader[T] {
def read(conf: String): T
}
implicit object BooleanConfigReader extends ConfigReader[Boolean] {
override def read(conf: String): Boolean = conf.toLowerCase() match {
case "true" => true
case "false" => false
}
}
implicit object ArrayConfigReader extends ConfigReader[Array[String]] {
override def read(s: String): Array[String] = {
LoadedProperties.getList(s)
}
}
var config: Properties = new Properties()
def getConfigs: Properties = config
def loadConfigs(prop: Properties): Properties = {
config = prop
config
}
def getConfigAs[T](key: String)(implicit reader: ConfigReader[T]): T = {
val prop = config.getProperty(key)
if (prop == null)
throw new Exception("Key not found in config")
reader.read(prop)
}
}
val props = new Properties()
props.setProperty("a", "false")
props.setProperty("b", "some")
hasConfig.loadConfigs(props)
hasConfig.getConfigAs[Boolean]("a")
hasConfig.getConfigAs[Array[String]]("a")
I have the following class:
abstract class IRDMessage extends Ordered[IRDMessage] {
val messageType: MessageType.Type
val timestamp: DateTime
val content: AnyRef
def compare(that: IRDMessage): Int = {
val res = timestamp compareTo that.timestamp
res
}
override def equals(obj: Any): Boolean = obj match{
case message: IRDMessage => compareTo(message) == 0
case _ => false
}
}
I have a couple of concrete implementations as well. However, when I try to say a == b of any subtype of IRDMessage the equals method does not get called and it simply compares references (default equals implementation). Any ideas what might be causing this?
The subclasses are simple case classes btw.
This does actually work given the following simplified example:
object MessageTest {
def main(args: Array[String]) {
val m1 = MessageImpl("foo")
val m2 = MessageImpl("bar")
m1 == m2
}
}
abstract class IRDMessage extends Ordered[IRDMessage] {
val content: AnyRef
override def equals(obj: Any): Boolean = {
println("in here")
obj match{
case message: IRDMessage => compareTo(message) == 0
case _ => false
}
}
}
case class MessageImpl(content:String) extends IRDMessage{
override def compare(that:IRDMessage) = 0
}
Can you post a little more code, specifically one of your sample case classes? I noticed if I defined the case class like so:
case class MessageImpl extends IRDMessage{
var content = "foo"
override def compare(that:IRDMessage) = 0
}
It does not work as expected.
What must I do in order to be able to return an Iterator from a method/class ? How would one add that trait to a class?
You can extend Iterator, which will require that you implement the next and hasNext methods:
class MyAnswer extends Iterator[Int] {
def hasNext = true
def next = 42
}
But, you will get more flexibility if you extend Iterable, which requires you implement elements (or iterator in 2.8):
class MyAnswer extends Iterable[Int] {
def iterator = new Iterator[Int] {
def hasNext = true
def next = 42
}
}
A common idiom seems to be to expose an iterator to some private collection, like this:
class MyStooges extends Iterable[String] {
private val stooges = List("Moe", "Larry", "Curly")
def iterator = stooges.iterator
}
For a method, just yield:
def odd(from: Int, to: Int): List[Int] =
for (i <- List.range(from, to) if i % 2 == 1) yield i
These two answers had help from the posts below and thanks #Dima.
How do I implement an iterator for an existing singly linked list?
why does this iterable implementation produce a stackoverflow?
Lets assume you have a class linked list. And the requirement is to print all the elements in the list.
trait LinkedList {
def nodeValue: Int
def tailList: LinkedList
}
class Node(val nodeValue: Int, val tailList: LinkedList) extends LinkedList
object Nil extends LinkedList {
def nodeValue = throw new IllegalAccessException("head of Nil")
def tailList = throw new IllegalAccessException("tail of Nil")
}
val singleLinkedList = new Node(1,Nil)
val chainedLinkedList = new Node(2,singleLinkedList)
print(chainedLinkedList)
A$A44$A$A44$Node#7b7a2c78res0: Unit = ()
Now Lets implement iterator to this class.
trait LinkedList extends Iterator[Int]{
def nodeValue: Int
def tailList: LinkedList
}
class Node(val nodeValue: Int, val tailList: LinkedList) extends LinkedList {
var ptr: LinkedList = this
//The following two are mandatory for extending Iterator
override def hasNext: Boolean = ptr match { case Nil => false; case _=> true}
override def next(): Int = {
val result = ptr.nodeValue
ptr = ptr.tailList
result
}
}
object Nil extends LinkedList {
def nodeValue = throw new IllegalAccessException("head of Nil")
def tailList = throw new IllegalAccessException("tail of Nil")
//The following two are mandatory for extending Iterator
override def hasNext: Boolean = false
override def next(): Int = throw new IllegalAccessException("next of Nil")
}
val singleLinkedList = new Node(1,Nil)
val chainedLinkedList = new Node(2,singleLinkedList)
//Printing this first Time
chainedLinkedList.foreach(println)
//Prints 2 1
//Printing second Time
chainedLinkedList.foreach(println)
//No output
In the iterator implementation, once ptr reached the end, it could did not advance back. Iterable implementation solves this.
trait LinkedList extends Iterable[Int]{
val nodeValue: Int
val tailList: LinkedList
override def toString(): String = this.mkString(" -> ")
}
class Node(val nodeValue: Int, val tailList: LinkedList) extends LinkedList {
override def iterator: Iterator[Int] = Iterator
.iterate(this: LinkedList)(_.tailList)
.takeWhile(_ != Nil)
.map(_.nodeValue)
}
object Nil extends LinkedList {
lazy val nodeValue= throw new IllegalAccessException("head of Nil")
lazy val tailList = throw new IllegalAccessException("tail of Nil")
override def iterator: Iterator[Int] = Iterator.empty
}
val singleLinkedList = new Node(1,Nil)
val chainedLinkedList = new Node(2,singleLinkedList)
//Printing this first Time
chainedLinkedList.foreach(println)
Output 2 -> 1
chainedLinkedList.foreach(println)
Output 2 -> 1