递归打印方法中的数组

时间:2011-11-16 13:23:44

标签: arrays scala

我正在尝试进行println替换,以更易读的格式输出嵌套集合。最好用一个例子说明:我希望List(Set(Vector(1.0,1.1), Vector(0d)), Set(Vector("a", "b", "c"), Vector("x", "y")))打印为

List
  Set
    Vector(1.0, 1.1)
    Vector(0.0)
  Set
    Vector(a, b, c)
    Vector(x, y)

如果没有类型擦除,这将更容易,但我想出了

def rprint(a: Any, indent: Int = 0): Unit = a match {
  case x: Traversable[_] =>
    if (x.isEmpty)
      rprint(x.toString, indent)
    else x.head match {
      case y: Traversable[_] => {
        rprint(x.toString.takeWhile(_ != '('), indent)
        x foreach {i => rprint(i, indent + 2)}
      }
      case y => rprint(x.toString, indent)
    }
  case x => println(" " * indent + x)
}

我正在努力让这个与Arrays很好地协同工作,没有大量的代码重复。我希望他们和其他系列一样工作。具体做法是:

  • 数组不是Traversable

  • 可以使用genericArrayOps将数组转换为TraversableOnce的ArrayOps,但TraversableOnce没有head方法,所以我看不清楚获取元素以检查其类型

  • toString与其他馆藏不同(使用.deep

将Arrays合并到此方法中的最佳方法是什么,或者是否有更好的方法可以更好地工作?

4 个答案:

答案 0 :(得分:1)

不要转换为ArrayOps,而是尝试WrappedArray,它有一个head方法并且可以遍历。

答案 1 :(得分:1)

尝试在匹配短语中使用更多常规类型,例如GenTraversable以存在隐式转换。

import scala.collection.GenTraversable

def rprint[T](a: T, indent: Int = 0): Unit = a match {
  case x: String => println(" "*indent + '"' + x + '"')
  case x: GenTraversable[_] =>
    println(" "*indent + (x.stringPrefix))
    x foreach (rprint(_, indent+2))
  case x: Array[_] =>
    println(" "*indent + (a.getClass.getSimpleName))
    x foreach (rprint(_, indent+2))
  case x => println(" "*indent + x)
}

rprint(Map(1->"one",2->"two"))
rprint(List("one", "two"))           //I don't know why this type is printed weird: $colon$colon
rprint(Array(1,2))                   //This prints less weird: int[]

您可以为特定缺失类型(如元组)添加更多案例

我无法确定打印某些类型名称有什么问题(例如ListArray - 请参阅函数定义后的示例)。 a.getClass.getSimpleNamea.ToString都会返回有线字符串

我还尝试连接类型ArrayGenTraversable - 因为存在从ArrayWrapperArray <: GenTraversable的隐式转换。
下面的解决方案不满足,因为它打印“WrappedArray”而不是“Array”, 当我们用Array实例

调用函数时
case x: Array[_] => rprint(x:GenTraversable[_])

编辑:
我已将GenTraversable的名称提取器更改为a.stringPrefix

答案 2 :(得分:1)

为了使它更灵活,我正在定义一个包含实用程序方法和一个抽象方法的特征,以便它可以像Array(1,2).print那样使用:

trait Printable[T] {
  def str(indent: Int = 0): String
  def str: String = str(0)
  def print(indent: Int = 0): Unit = println(str(indent))
  def print: Unit = print(0)
}

然后隐含使其看起来像strprintAny的方法:

implicit def any2Printable(a: Any): Printable[Any] = new Printable[Any] {
  import collection._
  def name = a match {
    case a: Array[_] => "Array"
    case g: GenTraversableLike[_, _] => g.stringPrefix 
    case i: Iterator[_] => "Iterator"
    case _ => ""
  }
  object Iter {
    def unapply(a: Any): Option[GenIterable[_]] = a match {
      case a: Array[_] => Some(a.toIterable)
      case t: GenTraversableOnce[_] => Some(t.toIterable)
      case _ => None
    }
  }
  object Nested {
    def unapply(i: GenIterable[_]): Option[GenIterable[_]] = i match {
      case nested if i.exists{case Iter(j) =>true case _ =>false} => Some(nested)
      case _ => None
    }
  }
  def str(indent: Int = 0) = " " * indent + (a match {
    case Iter(i) if i.isEmpty => name + " <empty>"
    case Iter(Nested(i)) => name + "\n" + i.map(_.str(indent+2)).mkString("\n")
    case Iter(i) => name + i.map(_.toString).mkString("(", ", ", ")")
    case _ => a.toString
  })
}

这可以处理任意深度嵌套,但不会对不包含集合的集合使用多行 - 例如可以打印:

Array
  Set
    Array(1.0, 1.1)
    Vector <empty>
    Array <empty>
    Set
      Vector(a, b, c)
      Vector(x, y)
      List
        Set
          Array(1.0, 1.1)
          Vector(0.0)
        Set
          Vector(a, b, c)
          Vector(x, y)

答案 3 :(得分:0)

我不打算回答我自己的问题,但我有一些有效的方法。我认为它可以改进很多,所以建议值得赞赏。那里仍然有重复和相当丑陋的演员。

  def rprint(a: Any, indent: Int = 0): Unit = {
    val (typeStr, fullStr) = a match {
      case x: collection.mutable.WrappedArray[_] => ("Array", x.deep.toString)
      case x: Traversable[_] => (x.stringPrefix, x.toString)
      case _ => ("", "")
    }
    a match {
      case x: Traversable[_] =>
        if (x.isEmpty)
          rprint(typeStr + " <empty>", indent)
        else 
          x.head match {
            case _: Array[_] => {
              rprint(typeStr, indent)
              x foreach {i => rprint(genericWrapArray(
                                       i.asInstanceOf[Array[_]]), indent + 2)}
            }
            case _: Traversable[_] => {
              rprint(typeStr, indent)
              x foreach {i => rprint(i, indent + 2)}
            }
            case _ => rprint(fullStr, indent)
          }
      case x: Array[_] => rprint(genericWrapArray(x))
      case x => println(" " * indent + x)
    }
  }

试验:

scala> rprint(List(Array(Vector(1.0,1.1), Vector(0d)), Array(Array("a", "b", "c"), Array("x", "y"))))
List
  Array
    Vector(1.0, 1.1)
    Vector(0.0)
  Array
    Array(a, b, c)
    Array(x, y)