在不使用变量的情况下尝试实现功能方式时,简单的命

时间:2014-07-01 12:15:59

标签: scala functional-programming

我有树状结构

class T {
  properties:P
  children:Seq[T]
}

我希望将它转换为另一个树状结构,其中一些转换应用于属性,而字段用于父节点:

class TT {
  properties:PP
  parent:TT
  children:Seq[TT]
}

无法找到以功能方式执行此操作的方法。你能帮忙吗?

特别是@ om-nom-nom难以想象应该做的工作的java代码:

public class Omnomnom {
    static class P {
        String value;
    }

    static class PP {
        String value;
    }

    static class T {
        P properties;
        List<T> children;
    }

    static class TT {
        PP properties;
        TT parent;
        List<TT> children;
    }

    static PP transform_P_into_PP(P properties) {
        PP result = new PP();
        result.value = properties.value + "pff";
        return result;
    }

    public static TT transform_T_into_TT(T node, TT parent){
        TT current = new TT();
        current.parent = parent;
        current.properties = transform_P_into_PP(node.properties);

        List<TT> children = new LinkedList<>();
        current.children = children;

        for(T child : node.children) {
            children.add(transform_T_into_TT(child,current));
        }
        return current;
    }

    public static void main(String [] args){
        T rootT = new T(); 
        TT rootTT = transform_T_into_TT(rootT,null);
    }
}

1 个答案:

答案 0 :(得分:5)

我个人认为在这种情况下功能解决方案非常清晰。首先,我将修复您的定义,这些定义无法编译:

// Dummy definitions for the sake of a complete working example.
type P = Int
type PP = String

trait T {
  def properties: P
  def children: Seq[T]
}

trait TT {
  def properties: PP
  def parent: Option[TT]
  def children: Seq[TT]
}

我所做的一个实质性改变是parent的类型。根节点没有父节点,如果我们的目标是功能方法,我们不想使用null,因此我们将其设为可选节点。现在转换定义非常简单:

def transform(f: P => PP)(t: T): TT = {
  def transformWithParent(op: Option[TT])(t: T): TT = new TT {
    val properties = f(t.properties)
    val parent = op
    val children: Seq[TT] = t.children.map(transformWithParent(Some(this)))
  }

  transformWithParent(None)(t)
}

让我们测试一下:

val myTree = new T {
  val properties = 3

  val children = Seq(
    new T {
      val properties = 4
      val children = Seq.empty
    },
    new T {
      val properties = 5
      val children = Seq.empty
    }
  )
}

val newTree = transform(_.toString)(myTree)

然后例如我们可以查看根的第二个子节点,找到它的父节点(当然是根节点),并获取父节点的值:

scala> newTree.children(1).parent.map(_.properties)
res0: Option[PP] = Some(3)

完全符合预期。