2011-11-16 75 views
2

我试图做一个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) 
} 

我m正在努力使其与数组很好地协作,而没有大量的代码重复。我希望他们能够像其他收藏一样工作。具体做法是:

  • 数组不是Traversable

  • 可以转换使用genericArrayOps到ArrayOps这是TraversableOnce阵列,但TraversableOnce没有一个head方法,所以我不能看到如何获取元素以检查它的类型

  • toString不起作用很喜欢其他收藏品(使用.deep

将数组并入该方法的最佳方法是什么?或者有什么不同的方法可以更好地工作?

回答

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) 
} 

然后暗示使它看起来像strprint是方法Any

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) 
+0

这非常酷,它也处理迭代器,这太棒了! (我现在可能会去攻击我的scala-library.jar以将其包含在Predef中) –

1

而不是转换为ArrayOps,请尝试一个WrappedArray,它具有头部方法并且可以穿过。

1

尝试tu在匹配短语中使用更一般的类型,如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实例

case x: Array[_] => rprint(x:GenTraversable[_]) 

编辑:
我已经改变名称提取器GenTraversable到a.stringPrefix

+0

这并不编译(对我来说,在REPL,v2.9.0-1)'错误:类型不匹配;发现:a.type(具有基础类型T)需要:?{val getClass:?}'。我正在寻找'toString'或'stringPrefix'方法中的显示名称,而不是类名,它们可能不同(例如'List'的具体类型是'::')。 –

+0

我不知道。对我来说一切都很好。 –

+0

升级到2.9.1后,我得到了它的工作。我会用''Array''替换'(a.getClass.getSimpleName)'。这并不完全符合指定的内容,因为它在各自的行上输出集合/数组元素,而不是表示集合的字符串(请参阅测试用例的OP)。这就是使问题变得不重要的原因。 –

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)