I have the following code snippet:
object Main1 extends App {
sealed trait XYZ
{
def id : String
}
class Test() extends XYZ {
override def id: String = "Test"
}
class ABC() extends XYZ {
override def id: String = "ABC"
}
val a: List[XYZ] = List(new Test(), new ABC())
val b: Map[String, List[XYZ]] = a.groupBy(_.id)
println(b)
val c: List[XYZ] = List(new ABC(), new Test())
val d: Map[String, List[XYZ]] = c.groupBy(_.id)
println(d)
}
The output is as follows:
Map(Test -> List(Main1$Test#7dc5e7b4), ABC -> List(Main1$ABC#1ee0005))
Map(Test -> List(Main1$Test#3d012ddd), ABC -> List(Main1$ABC#6f2b958e))
How can I maintain the order in the result like in the input collection?
If you are not limited to use immutable collections only then it can be easily done with mutable.LinkedHashMap:
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
object Main1 extends App {
sealed trait XYZ
{
def id : String
}
class Test() extends XYZ {
override def id: String = "Test"
}
class ABC() extends XYZ {
override def id: String = "ABC"
}
val a: List[XYZ] = List(new Test(), new ABC())
val b: mutable.LinkedHashMap[String, ArrayBuffer[XYZ]] = a.foldLeft(mutable.LinkedHashMap.empty[String, ArrayBuffer[XYZ]]) { (m, x) =>
m.getOrElseUpdate(x.id, new ArrayBuffer[XYZ]) += x
m
}
println(b)
val c: List[XYZ] = List(new ABC(), new Test())
val d: mutable.LinkedHashMap[String, ArrayBuffer[XYZ]] = c.foldLeft(mutable.LinkedHashMap.empty[String, ArrayBuffer[XYZ]]) { (m, x) =>
m.getOrElseUpdate(x.id, new ArrayBuffer[XYZ]) += x
m
}
println(d)
}
Output maintains the order of the input collection:
LinkedHashMap(Test -> ArrayBuffer(com.github.plokhotnyuk.jsoniter_scala.examples.Main1$Test#56cbfb61), ABC -> ArrayBuffer(com.github.plokhotnyuk.jsoniter_scala.examples.Main1$ABC#1134affc))
LinkedHashMap(ABC -> ArrayBuffer(com.github.plokhotnyuk.jsoniter_scala.examples.Main1$ABC#1b0375b3), Test -> ArrayBuffer(com.github.plokhotnyuk.jsoniter_scala.examples.Main1$Test#2f7c7260))
Related
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.
I have this code
import scala.reflect.ClassTag
case class Data[T: ClassTag](list: List[T]) {
}
trait Transformation {
type T
type U
def transform(data: Data[T]) : Data[U]
}
class FromInt2String extends Transformation {
override type T = Int
override type U = String
override def transform(data: Data[T]) = new Data(List("1", "2", "3"))
}
class FromString2Int extends Transformation {
override type T = String
override type U = Int
override def transform(data: Data[T]) = new Data(List(1, 2, 3))
}
object Test extends App {
override def main(args: Array[String]) {
val data = new Data(List(1, 2, 3))
val int2String = new FromInt2String()
val data2 = int2String.transform(data)
val string2Int = new FromString2Int()
val data3 = string2Int.transform(data2)
val transformations = List(int2String, string2Int)
val data4 = transformations.foldLeft(data)((data, transformation) => {
transformation.transform(data)
})
}
}
The problem is in the foldLeft method. I can't do it because the type isn't compatible but I need to apply all the transforms in my initial object data
Any ideas how to do it?
Thanks
I've solved it using shapeless and this post
import scala.reflect.ClassTag
import shapeless._
object andThen extends Poly2 {
implicit def functions[A, B, C] = at[A => B, B => C](_ andThen _)
}
case class Data[T: ClassTag](list: List[T]) {
}
trait Transformation {
type T
type U
def transform(data: Data[T]) : Data[U]
}
class FromInt2String extends Transformation {
override type T = Int
override type U = String
override def transform(data: Data[T]) = new Data(List("1s", "2s", "3s"))
}
class FromString2Int extends Transformation {
override type T = String
override type U = Int
override def transform(data: Data[T]) = new Data(List(4, 5, 6))
}
object Test extends App {
override def main(args: Array[String]) {
val data = new Data(List(1, 2, 3))
println(data)
val int2String = new FromInt2String()
val data2 = int2String.transform(data)
println(data2)
val string2Int = new FromString2Int()
val data3 = string2Int.transform(data2)
println(data3)
val transformations = int2String.transform _ :: string2Int.transform _ :: HNil
val functions = transformations.reduceLeft(andThen)
val data4 = functions(data)
println(data4)
}
}
Thanks to all of you that help me
I have the following code, written in Scala 2.10.0:
trait A[T <: B] {
self : { def foo() } =>
val action : ()=>Unit = this.foo _
//wanna make default for this
val construction : String=>T
def bar()(implicit x : String) : T = {
action()
val destination = construction(x)
destination.baz()
destination
}
}
trait B { def baz() {} }
class Xlass { def foo() {} }
class Klass(a : String)(implicit val x : String) extends B {
val f = new Xlass with A[Klass] {
//boilerplate!
val construction = new Klass(_)
}
}
implicit val x = "Something"
val destination = new Klass("some a").f.bar()
I wonder, is it possible to make a default for construction, such as val construction = new T(_)?
I've tried several options for now, but none of them works with all the characteristics of this code, such as use of type bounds, implicits and structural typing. As far as I could get is this, but it fails with scala.ScalaReflectionException: free type T is not a class:
import reflect.runtime.universe._
val tT = weakTypeTag[T]
...
val privConstruction =
x : String =>
runtimeMirror(tT.mirror.getClass.getClassLoader)
//fails here with scala.ScalaReflectionException: free type T is not a class
.reflectClass(tT.tpe.typeSymbol.asClass)
.reflectConstructor(tT.tpe.members.head.asMethod)(x).asInstanceOf[T]
So, finally, I did it:
trait A[T <: B] {
self : { def foo() } =>
val action : ()=>Unit = this.foo _
def construction(x: String)(implicit tag : reflect.ClassTag[T]) : T = {
tag.runtimeClass.getConstructor(classOf[String], classOf[String]).newInstance(x, x).asInstanceOf[T]
}
def bar()(implicit x : String, tag : reflect.ClassTag[T]) : T = {
action()
val destination = construction(x)
destination.baz()
destination
}
}
trait B { def baz() {} }
class Xlass { def foo() {} }
class Klass(a : String)(implicit val x : String) extends B {
val f = new Xlass with A[Klass]
}
implicit val x = "Something"
val destination = new Klass("some a").f.bar()
I'm not sure if i got the topic right. I'll try to describe the problem.
I have one common field trait. StringField and IntField extend this class:
trait BaseField[T] {
def name = "field"
var owner : FieldContainer
var value : T
def set(value : T) {
this.value = value
this.owner.fields.put(name, this)
}
}
class StringField extends BaseField[String]
class IntField extends BaseField[Int]
How do i implement the FieldContainer class? What i want is to match the FieldTypes later on:
val fieldContainer = {...init code here...}
fieldContainer.fields foreach {
field -> {
field match {
case f: StringField => println("String")
case f: IntField => println("Int")
case _ => println("Unknown")
}
}
}
This is my FieldContainer (so far)
trait FieldContainer {
private metaFields : HashMap[String, Any] = new HashMap[String, Any]
def fields : HashMap[String, Any] = this.metaFields
}
And i use it in that way:
class Pizza extends FieldContainer {
object name extends StringField(this) {
override def name = "pizza_name"
}
object pieces extends IntField(this) {
override def name = "pieces_count"
}
}
Fields don't need to know their owners.
class BaseField[T](initValue: T, val name: String = "field") {
private[this] var _value: T = initValue
def apply() = _value
def update(v: T) { _value = v }
override def toString(): String = name + "(" + apply() + ")"
}
class StringField(initValue: String, name: String = "field") extends BaseField[String](initValue, name)
class IntField(initValue: Int, name: String = "field") extends BaseField[Int](initValue, name)
trait FieldContainer {
protected def addField[C <: BaseField[_]](field: C): C = {
_fields += (field.name -> field)
field
}
protected def stringField(initValue: String, name: String): StringField =
addField(new StringField(initValue, name))
protected def intField(initValue: Int, name: String): IntField =
addField(new IntField(initValue, name))
private var _fields : Map[String, Any] = Map[String, Any]()
def fields : Map[String, Any] = _fields
}
Objects (singletons) initialized when first accessed, so you should use val instead of object for fields:
class Pizza extends FieldContainer {
val name = stringField("", "pizza_name")
val pieces = intField(0, "pieces_count")
val mass: BaseField[Double] = addField(new BaseField[Double](0, "mass"))
}
Usage:
scala> val p = new Pizza()
p: Pizza = Pizza#8c61644
scala> p.fields
res0: Map[String,Any] = Map(pizza_name -> pizza_name(), pieces_count -> pieces_count(0), mass -> mass(0.0))
scala> p.name() = "new name"
scala> p.pieces() = 10
scala> p.mass() = 0.5
scala> p.fields
res4: Map[String,Any] = Map(pizza_name -> pizza_name(new name), pieces_count -> pieces_count(10), mass -> mass(0.5))
scala> p.name()
res5: String = new name
scala> p.pieces()
res6: Int = 10
scala> p.mass
res7: BaseField[Double] = mass(0.5)
I have the following code:
class Parameterizable{
var map: Map[String, String] = new scala.collection.immutable.HashMap()
def put(entry: Tuple2[String, String]) = {
map = map + entry; this
}
}
class Query() extends Parameterizable{
override def toString = {
map.isEmpty match{
case true => ""
case false => "?" + map.map{case (key, value) => key + "=" + value}.mkString("&")
}
}
}
trait PageParameter extends Parameterizable{
def page(page: Int) = put(("page" -> page.toString))
def pageSize(pageSize: Int) = put(("pagesize" -> pageSize.toString))
}
trait DateParameter extends Parameterizable{
def fromDate(date: java.util.Date) = put(("fromdate" -> (date.getTime()/1000L).toString()))
def toDate(date: java.util.Date) = put(("todate" -> (date.getTime()/1000L).toString()))
}
//and other similar traits
I would like to do something like:
class ExtendedQuery extends Query with PageParameter with DateParameter
val query = new ExtendedQuery
query.page(4).pageSize(5).fromDate(new java.util.Date)
or:
query.and().page(4).and().pageSize(5).and().fromDate(new java.util.Date)
Is it possible in Scala?
You can declare the methods as returning this.type and then return this from them:
trait PageParameter extends Parameterizable{
def page(page: Int) : this.type = { put(("page" -> page.toString)); this }
def pageSize(pageSize: Int): this.type = { put(("pagesize" -> pageSize.toString)); this }
}
At the use-site, you can then chain the calls as you wanted. See this example:
scala> trait Wibble {
| def foo : this.type = { println("foo"); this }
| }
defined trait Wibble
scala> trait Wobble extends Wibble {
| def bar: this.type = { println("bar"); this }
| }
defined trait Wobble
scala> trait Wubble extends Wibble {
| def baz: this.type = { println("baz"); this }
| }
defined trait Wubble
Now I can test it
scala> new Wibble with Wobble with Wubble
res0: java.lang.Object with Wibble with Wobble with Wubble = $anon$1#937e20
scala> res0.bar.baz.foo
bar
baz
foo
res1: res0.type = $anon$1#937e20