I have this tree structure
sealed trait Tree
case class Node(var left: Tree, var right: Tree, var value: String) extends Tree
case object EmptyNode extends Tree
and a Tree object called myTree. I want to make another tree with the exact same structure and values called otherTree, but myTree.clone() does not work. What else can I do?
Something like this will copy your Tree:
def copyTree(t:Tree):Tree = {
t match {
case EmptyNode => EmptyNode
case Node(left, right, value) => Node(copyTree(left), copyTree(right), value)
}
}
Just for completeness - as the question asks for 'How to copy...' and you mentioned clone(): You can copy case classes with the copy() method. Yet it won't help with a tree structure that is mutable. But with an immutable structure (as Gregor suggests above), e.g. like this
sealed trait Tree
case class Node(left: Tree, right: Tree, value: String) extends Tree
case object EmptyNode extends Tree { override def toString = " _ " }
and some data
scala> val leaf1 = Node(EmptyNode, EmptyNode, "leaf1")
scala> val leaf2 = Node(EmptyNode, EmptyNode, "leaf2")
scala> val tree1 = Node(leaf1, leaf2, "tree1")
scala> tree1
res0: Node = Node(Node( _ , _ ,leaf1),Node( _ , _ ,leaf2),tree1)
you can copy your tree like this
scala> val tree2 = tree1.copy(value = "tree2")
tree2: Node = Node(Node( _ , _ ,leaf1),Node( _ , _ ,leaf2),tree2)
or
scala> val tree3 = Node(tree1.left, tree1.right, "tree3")
tree3: Node = Node(Node( _ , _ ,leaf1),Node( _ , _ ,leaf2),tree3)
As usual with immutable instances, for updates you would need to create new tree structures for example using recursive operations as in Noah's answer.
Related
Two objects extend a base object like this:
trait Component
class ComponentA extends Component
class ComponentB extends Component
Let's say I have some objects instantiated:
val a = new ComponentA
val a2 = new ComponentA
val b = new ComponentB
I'm given a list of type Component, like this:
val components = List[Components](a, a2, b)
What I want to do is have a function that takes a list of mixed type and transforms it into an n-tuple of lists containing only one type. So for example, components would break down like this:
transform.apply(components) = (List(a, a2), List(b))
The nonfunctional, grotesque, Frankensteinian way to do this is:
def apply(c: List[Component]) = {
var aComponents = new ListBuffer[ComponentA]()
var bComponents = new ListBuffer[ComponentB]()
for (c <- components) {
c match {
case aType: ComponentA => aComponents += aType
case bType: ComponentB => bComponents += bType
case _ => None
}
}
aComponents -> bComponents
}
Obviously there's tons of drawbacks to this method:
In my case, I have two component types. But this case does not generalize to produce an n-tuple for n-components.
It's not functional. (Uses mutable ListBuffer, doesn't leverage the Collections library.)
It's ugly. Like really ugly. I cannot over-emphasize how ugly it is.
Is there a way I can get this accomplished with FP in Scala? My initial thought was to use some sort of groupBy function with an internal case/match for type inspection?
Well, why not just use the groupBy with your class like:
c.groupBy(_.getClass).values
This will already give you a List of Lists with the grouped instances in it. Getting a tuple is more complicated as you need to know the type beforehand. There is solutions using Shapeless (Convert a Scala list to a tuple?) but not sure you really have to go that far as your original solution seems to work without an actual tuple.
I would use collect:
val aList = c.collect { case a: ComponentA => a }
val bList = c.collect { case b: ComponentB => b }
val res = (aList, bList)
Consider using foldRight to traverse the components list to assemble the (List[ComponentA], List[ComponentB]) tuple:
components.foldRight( (List[ComponentA](), List[ComponentB]()) )(
(x, acc) => x match {
case x: ComponentA => (x :: acc._1, acc._2)
case x: ComponentB => (acc._1, x :: acc._2)
case _ => acc
}
)
// res1: (List[ComponentA], List[ComponentB]) =
// (List(ComponentA#24a298a6, ComponentA#74fe5966), List(ComponentB#2bfbffb2))
I have some problem in scala order implicit, can someone help me?
Below are some classes definition, and what I want to do is to compare Leaf and Node through it's 'popularity'.
class Tree
case class EmptyTree() extends Tree
case class Leaf(label: String, popularity: Double) extends Tree
case class Node(popularity: Double, left: Tree, right: Tree) extends Tree
for exampel:
val a = Leaf("a",10)
val b = Leaf("b",20)
val c = Node(30,a,b)
if we want to compare a and b through it's popularity, it is easy to do by adding the implicit transformations, like that:
implicit val leavesOrder = new Ordering[Leaf] {
override def compare(x: Leaf, y: Leaf) =
implicitly[Ordering[Double]].compare(x.popularity, y.popularity)
}
but if I want to compare a and c through it's popularity, I am confused about it and don't konw how to add the implicit transformations?
Can someone help me?
You can create an implicit Ordering for Tree if you want to compare Leafs and Nodes.
Here's some (incomplete) code, on how you could do that:
implicit val treeOrder = new Ordering[Tree] {
override def compare(x: Tree, y: Tree) = (x,y) match {
case (Leaf(_,xP), Leaf(_,yP)) => xP compare yP
case (Node(xP,_,_), Leaf(_,yP)) => xP compare yP
case (Node(xP,_,_), Node(yP,_,_)) => xP compare yP
case (EmptyTree(), _) => -1
/* Add the rest of the cases here */
}
}
Bonus points for changing Tree to be a sealed trait, so that the compiler can tell you when your pattern matching is incomplete :)
Id do something like this. Change your Tree class to a sealed trait this means the pattern matching is exhaustive so the compiler can tell you if your missing something. Then you need to match on each of the types that a Tree can be. Not all of them have a popularity.
sealed trait Tree
case object EmptyTree extends Tree
case class Leaf(label: String, popularity: Double) extends Tree
case class Node(popularity: Double, left: Tree, right: Tree) extends Tree
implicit val treeOrdering = new Ordering[Tree] {
private val doubleOrdering = implicitly[Ordering[Double]]
def compare(a: Tree, b: Tree): Int = {
(a, b) match {
case (Node(p1, _, _), Node(p2, _, _)) => doubleOrdering.compare(p1, p2)
case (Leaf(_, p1), Node(p2, _, _)) => doubleOrdering.compare(p1, p2)
case (Node(p1, _, _), Leaf(_, p2)) => doubleOrdering.compare(p1, p2)
case (Leaf(_, p1), Leaf(_, p2)) => doubleOrdering.compare(p1, p2)
case (EmptyTree, _) => -1
case (_, EmptyTree) => 1
}
}
}
Is there an elegant way to do something like the following example using just one case statement?
foobar match {
case Node(Leaf(key, value), parent, qux) => {
// Do something with parent & qux
}
case Node(parent, Leaf(key, value), qux) => {
// Do something with parent & qux (code is the same as in the previous case)
}
// other cases
}
For an understanding of what is going on here: foobar is a node of a binary tree, and I match the cases when one of the node's ancestors is a Leaf node. These are the classes used:
abstract class Tree
case class Node(left: Tree, right: Tree, critBit: Int) extends Tree
case class Leaf(key: String, value:String) extends Tree
You can use a custom extractor to abstract the matching part away from the logic part:
object Leafed {
def unapply(tree: Tree) = tree match {
case Node(Leaf(_, _), parent, qux) => Some((parent, qux))
case Node(parent, Leaf(_, _), qux) => Some((parent, qux))
case _ => None
}
}
And then you can define methods like this:
def doSomething(tree: Tree): Int = tree match {
case Leafed(parent, qux) => qux
case _ => -100
}
Which you can use like this:
scala> val leaf = Leaf("foo", "bar")
leaf: Leaf = Leaf(foo,bar)
scala> doSomething(leaf)
res7: Int = -100
scala> doSomething(Node(leaf, Node(leaf, leaf, 5), 10))
res8: Int = 10
scala> doSomething(Node(Node(leaf, leaf, 5), leaf, 10))
res9: Int = 10
Otherwise you're out of luck—as Marth notes above, pattern alternatives aren't going to help you here.
I want to build a Scala DSL to convert from a existing structure of Java POJOs to a structure equivalent to a Map.
However the incoming objects structure is very likely to contain a lot of null references, which will result in no value in the output map.
The performance is very important in this context so I need to avoid both reflection and throw/catch NPE.
I have considered already this topic which does not meet with my requirements.
I think the answer may lie in the usage of macros to generate some special type but I have no experience in the usage of scala macros.
More formally :
POJO classes provided by project : (there will be like 50 POJO, nested, so I want a solution which does not require to hand-write and maintain a class or trait for each of them)
case class Level1(
#BeanProperty var a: String,
#BeanProperty var b: Int)
case class Level2(
#BeanProperty var p: Level1,
#BeanProperty var b: Int)
expected behaviour :
println(convert(null)) // == Map()
println(convert(Level2(null, 3))) // == Map("l2.b" -> 3)
println(convert(Level2(Level1("a", 2), 3))) // == Map(l2.p.a -> a, l2.p.b -> 2, l2.b -> 3)
correct implementation but I want an easier DSL for writing the mappings
implicit def toOptionBuilder[T](f: => T) = new {
def ? : Option[T] = Option(f)
}
def convert(l2: Level2): Map[String, _] = l2? match {
case None => Map()
case Some(o2) => convert(o2.p, "l2.p.") + ("l2.b" -> o2.b)
}
def convert(l1: Level1, prefix: String = ""): Map[String, _] = l1? match {
case None => Map()
case Some(o1) => Map(
prefix + "a" -> o1.a,
prefix + "b" -> o1.b)
}
Here is how I want to write with a DSL :
def convertDsl(l2:Level2)={
Map(
"l2.b" -> l2?.b,
"l2.p.a" -> l2?.l1?.a,
"l2.p.b" -> l2?.l1?.b
)
}
Note that it is perfectly fine for me to specify that the property is optional with '?'.
What I want is to generate statically using a macro a method l2.?l1 or l2?.l1 which returns Option[Level1] (so type checking is done correctly in my DSL).
I couldn't refine it down to precisely the syntax you gave above, but generally, something like this might work:
sealed trait FieldSpec
sealed trait ValueFieldSpec[+T] extends FieldSpec
{
def value: Option[T]
}
case class IntFieldSpec(value: Option[Int]) extends ValueFieldSpec[Int]
case class StringFieldSpec(value: Option[String]) extends ValueFieldSpec[String]
case class Level1FieldSpec(input: Option[Level1]) extends FieldSpec
{
def a: ValueFieldSpec[_] = StringFieldSpec(input.map(_.a))
def b: ValueFieldSpec[_] = IntFieldSpec(input.map(_.b))
}
case class Level2FieldSpec(input: Option[Level2]) extends FieldSpec
{
def b: ValueFieldSpec[_] = IntFieldSpec(input.map(_.b))
def l1 = Level1FieldSpec(input.map(_.p))
}
case class SpecArrowAssoc(str: String)
{
def ->(value: ValueFieldSpec[_]) = (str, value)
}
implicit def str2SpecArrowAssoc(str: String) = SpecArrowAssoc(str)
implicit def Level2ToFieldSpec(input: Option[Level2]) = Level2FieldSpec(input)
def map(fields: (String, ValueFieldSpec[_])*): Map[String, _] =
Map[String, Any]((for {
field <- fields
value <- field._2.value
} yield (field._1, value)):_*)
def convertDsl(implicit l2: Level2): Map[String, _] =
{
map(
"l2.b" -> l2.?.b,
"l2.p.a" -> l2.?.l1.a,
"l2.p.b" -> l2.?.l1.b
)
}
Then we get:
scala> val myL2 = Level2(Level1("a", 2), 3)
myL2: Level2 = Level2(Level1(a,2),3)
scala> convertDsl(myL2)
res0: scala.collection.immutable.Map[String,Any] = Map(l2.b -> 3, l2.p.a -> a, l2.p.b -> 2)
Note that the DSL uses '.?' rather than just '?' as the only way I could see around Scala's trouble with semicolon inference and postfix operators (see, eg., #0__ 's answer to scala syntactic suger question).
Also, the strings you can provide are arbitrary (no checking or parsing of them is done), and this simplistic 'FieldSpec' hierarchy will assume that all your POJOs use 'a' for String fields and 'b' for Int fields etc.
With a bit of time and effort I'm sure this could be improved on.
What I need is a class X I can construct with a Map that takes Strings into either other Strings or Maps that take Strings into Strings, and then an arbitrary number of other instances of X. With my limited grasp of Scala, I know I can do this:
class Person (stringParms : Map[String, String],
mapParms : Map[String, Map[String, String]],
children : List[X]) {
}
but that doesn't look very Scala-ish ("Scalish"? "Scalerific"? "Scalogical"?) I'd like to be able to do is the following:
Person bob = Person("name" -> "Bob", "pets" -> ("cat" -> "Mittens", "dog" -> "Spot"), "status" -> "asleep",
firstChild, secondChild)
I know I can get rid of the "new" by using the companion object and I'm sure I can look Scala varargs. What I'd like to know is:
How I can use -> (or some similarly plausible operator) to construct elements to be made into a Map in the construction?
How I can define a single map so either it can do an Option-like switch between two very disparate types or becomes a recursive tree, where each (named) node points to either a leaf in the form of a String or another node like itself?
The recursive version really appeals to me because, although it doesn't address a problem I actually have today, it maps neatly into a subset of JSON containing only objects and strings (no numbers or arrays).
Any help, as always, greatly appreciated.
-> is just a syntactic sugar to make a pair (A, B), so you can use it too. Map object takes a vararg of pairs:
def apply [A, B] (elems: (A, B)*) : Map[A, B]
You should first check out The Architecture of Scala Collections if you're interested in mimicking the collections library.
Having said that, I don't think the signature you proposed for Person looks like Map, because it expects variable argument, yet children are not continuous with the other (String, A) theme. If you say "child1" -> Alice, and internally store Alice seperately, you could define:
def apply(elems: (String, Any)*): Person
in the companion object. If Any is too loose, you could define PersonElem trait,
def apply(elems: (String, PersonElem)*): Person
and implicit conversion between String, Map[String, String], Person, etc to PersonElem.
This gets you almost there. There is still a Map I don't get easily rid of.
The basic approach is to have a somewhat artificial parameter types, which inherit from a common type. This way the apply method just takes a single vararg.
Using implicit conversion method I get rid of the ugly constructors for the parameter types
case class Child
case class Person(stringParms: Map[String, String],
mapParms: Map[String, Map[String, String]],
children: List[Child]) { }
sealed abstract class PersonParameter
case class MapParameter(tupel: (String, Map[String, String])) extends PersonParameter
case class StringParameter(tupel: (String, String)) extends PersonParameter
case class ChildParameter(child: Child) extends PersonParameter
object Person {
def apply(params: PersonParameter*): Person = {
var stringParms = Map[String, String]()
var mapParms = Map[String, Map[String, String]]()
var children = List[Child]()
for (p ← params) {
p match {
case StringParameter(t) ⇒ stringParms += t
case MapParameter(t) ⇒ mapParms += t
case ChildParameter(c) ⇒ children = c :: children
}
}
new Person(stringParms, mapParms, children)
}
implicit def tupel2StringParameter(t: (String, String)) = StringParameter(t)
implicit def child2ChildParameter(c: Child) = ChildParameter(c)
implicit def map2MapParameter(t: (String, Map[String, String])) = MapParameter(t)
def main(args: Array[String]) {
val firstChild = Child()
val secondChild = Child()
val bob: Person = Person("name" -> "Bob","pets" -> Map("cat" -> "Mittens", "dog" -> "Spot"),"status"
-> "asleep",
firstChild, secondChild)
println(bob)
} }
Here's one way:
sealed abstract class PersonParam
object PersonParam {
implicit def toTP(tuple: (String, String)): PersonParam = new TupleParam(tuple)
implicit def toMap(map: (String, Map[String, String])): PersonParam = new MapParam(map)
implicit def toSP(string: String): PersonParam = new StringParam(string)
}
class TupleParam(val tuple: (String, String)) extends PersonParam
class MapParam(val map: (String, Map[String, String])) extends PersonParam
class StringParam(val string: String) extends PersonParam
class Person(params: PersonParam*) {
val stringParams = Map(params collect { case parm: TupleParam => parm.tuple }: _*)
val mapParams = Map(params collect { case parm: MapParam => parm.map }: _*)
val children = params collect { case parm: StringParam => parm.string } toList
}
Usage:
scala> val bob = new Person("name" -> "Bob",
| "pets" -> Map("cat" -> "Mittens", "dog" -> "Spot"),
| "status" -> "asleep",
| "little bob", "little ann")
bob: Person = Person#5e5fada2
scala> bob.stringParams
res11: scala.collection.immutable.Map[String,String] = Map((name,Bob), (status,asleep))
scala> bob.mapParams
res12: scala.collection.immutable.Map[String,Map[String,String]] = Map((pets,Map(cat -> Mittens, dog -> Spot)))
scala> bob.children
res13: List[String] = List(little bob, little ann)