迭代case类元素的可能方法

时间:2017-08-21 11:57:30

标签: scala case-class

这是参考问题 Possible ways to pass argument of different type to case class

 trait Value

// define these in different files if you want
case class Student(value: String) extends Value
case class Employee(value: Double) extends Value
case class Department(value: Int) extends Value

case class Element(key: String, value: Value)

case class Grp (elements: List[Element] = Nil) extends Value {
  def add (key: String, value: Value): Grp = Grp(this.elements ++ List(Element(key, value)))

}

Grp()
  .add("2", Student("abc"))
  .add("3", Employee(100.20))
  .add("4", Department(10))
  .add("5", Grp().add("2", Student("xyz"))) // nested group

我想在Grp类中添加一个函数

def addSubGroup(group: Grp):Grp=group.elements.foreach(s=>add(s))

但由于return是Unit,因此不会添加元素

更新1

任何人都可以建议我解决这两种方法

  1. 我希望我的调用如下所示。我想要包含子组的val subgroup和addSubGroup将子组添加到组中。

      Grp()
      .add("2", Student("abc"))
      .add("3", Employee(100.20))
      .add("4", Department(10))
      .addSubGroup("5", Grp().add("2", Student("xyz"))) // nested group
    
  2. 更新2

    1. 如果我使用像case class GrpA() extends Grpcase class GrpB() extends Grp.这样的群组子类型但是禁止使用案例类继承
    2. 任何可能的方法来摆脱多个添加调用。

      注意:如果可能,请分享没有varargs的解决方案

2 个答案:

答案 0 :(得分:1)

您可以在配套对象中使用vararg方法清除多个add,例如

def apply(elements: (String, Value)*): Grp = Grp(elements.map(Element.tupled).toList)

群组连接可以像通常的++方法一样实施,如

def ++(that: Grp) = Grp(elements ++ that.elements) 

如果您希望您的小组成为某种可迭代的,尊重子群,您可以这样做,扩展Iterable[Element]并实施

def iterator: Iterator[Element] = elements.iterator.flatMap {
  case Element(name, sub: Grp) => sub.iterator
  case element                 => Iterator.single(element)
}

完整Grp代码示例:

case class Grp(elements: List[Element] = Nil) extends Value with Iterable[Element] {
  def add(key: String, value: Value): Grp = Grp(this.elements :+ Element(key, value))
  def ++(that: Grp) = Grp(elements ++ that.elements)
  def iterator: Iterator[Element] = elements.iterator.flatMap {
    case Element(name, sub: Grp) => sub.iterator
    case element                 => Iterator.single(element)
  }
}

object Grp {
  def apply(elements: (String, Value)*): Grp = Grp(elements.map(Element.tupled).toList)
}

val group = Grp("2" -> Student("abc"),
                "3" -> Employee(100.20)) ++
            Grp("4" -> Department(10),
                "5" -> Grp("2" -> Student("xyz"),
                           "6" -> Employee(200.3))) // nested group


group.foreach(println)
//Element(2,Student(abc))
//Element(3,Employee(100.2))
//Element(4,Department(10))
//Element(2,Student(xyz))
//Element(6,Employee(200.3))

更新A

您仍然可以使用add语法代替tuple seq factory:

val group = Grp()
            .add("2", Student("abc"))
            .add("3", Employee(100.20))
            .add("4", Department(10))
            .add("5", Grp()
                      .add("2", Student("xyz"))
                      .add("6", Employee(200.3))) // nested group

答案 1 :(得分:0)

如果允许稍微调整一下类型,我会使用类似的东西:

sealed trait Value

trait BaseValue extends Value

// define these in different files if you want
case class Student(value: String) extends BaseValue
case class Employee(value: Double) extends BaseValue
case class Department(value: Int) extends BaseValue

case class Grp(elements: List[(String, BaseValue)] = Nil,
               subGroups: List[(String, Grp)] = Nil) extends Value {
  def add(entries: (String, BaseValue)*): Grp = Grp(elements ++ entries, subGroups)
  def addSubGroup(entries: (String, Grp)*): Grp = Grp(elements, subGroups ++ entries)

}

Grp()
  .add("2" -> Student("abc"), "3" -> Employee(100.20), "4" -> Department(10)) // base elements
  .addSubGroup("5" -> Grp().add("2" ->Student("xyz"))) // nested group

这将产生以下结果:

res0: Grp = Grp(List((2,Student(abc)), (3,Employee(100.2)), (4,Department(10))),List((5,Grp(List((2,Student(xyz))),List()))))