2011-11-16 68 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)