How to perform pattern matching with vararg case classes?

≯℡__Kan透↙ 提交于 2019-12-05 13:44:33

问题


I have a set of case classes like this

abstract class Shape  
case class Rectangle(width: Int, height: Int) extends Shape  
case class Location(x: Int, y: Int, shape: Shape) extends Shape  
case class Circle(radius: Int) extends Shape  
case class Group(shape: Shape*) extends Shape

where basically Group is an array of shapes. I need to define a size method for computing sizes for rectangle, circle and location its straightforward just return one. But i am having difficulty for Group.

object size extends Shape{  
  def size(s: Any) : Int = s match {  
    case Rectangle(x,y) => 1  
    case Group  // how to do it? Also having case Group(shape : Shape*) gives an error  
    case Circle(r) => 1    
    case Location(x,y,shape) => 1   
  }  
}  

I know for Group i need to use map and fold left, but i really cant create a logic for it. Thanks


回答1:


Either of these will work, the second is probably preferred if a little weird at first glance. See 8.1.9 Pattern Sequences from the Scala Reference.

case g: Group => g.shape.map(size(_)).sum

case Group(ss @ _*) => ss.map(size(_)).sum

This is using Scala 2.8. sum may not work on older versions.




回答2:


The syntax for vararg pattern matching is somewhat strange.

def size(s: Shape) : Int = s match{
  case Rectangle(x,y) => 1
  case Circle(r) => 1
  case Location(x,y,shape) => 1
  case Group(shapes @ _*) => (0 /: shapes) { _ + size(_) }
}

Note that in the last line, you sum up the sizes of all sub-shapes starting with zero using the /:-notation for folds.


How folds work: Folds accumulate the elements of a sequence using a given function.

So in order to compute the sum of a list, we would write (Haskell-style)

fold (\total element -> total + element) 0 list

which would combine all elements of the list with the given addition function starting with 0 (and therefore compute the sum).

In Scala, we can write it this way:

(0 /: list) { (total, element) => total + element }

which can be simplified to

(0 /: list) { _ + _ }



回答3:


The first step is figuring out what you mean. The two most obvious choices are the total area covered by all the shapes, and the minimum rectangle containing them all. If for circles you return the actual area, they you probably have to go with the actual area.

There's no closed-form way to answer this. I might consider throwing a thousand random darts at a minimum enclosing rectangle and estimating the area as the percentage of darts that hit an occupied point. Is an estimate an acceptable response?

Are you guaranteed that all the shapes will be circles and rectangles? You might be able to cobble together a solution that would work for them. If Shapes might be extended further, then that won't work.




回答4:


For Location size should drill down to get size since shape could be group which causes a higher count

case Location(x,y,shape) => size(shape)

That is if size is the number of shapes in the Shape




回答5:


case g: Group => g.shape.map(size(_)).sum

case Group(ss @ *) => ss.map(size()).sum

both of these gives the error value sum is not a member of Seq[Int]
However this oen works
case Group(shapes @ _*) => (0 /: shapes) { _ + size(_)



来源:https://stackoverflow.com/questions/2274852/how-to-perform-pattern-matching-with-vararg-case-classes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!