我正在尝试进行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合并到此方法中的最佳方法是什么,或者是否有更好的方法可以更好地工作?
答案 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[]
您可以为特定缺失类型(如元组)添加更多案例
我无法确定打印某些类型名称有什么问题(例如List
和Array
- 请参阅函数定义后的示例)。 a.getClass.getSimpleName
和a.ToString
都会返回有线字符串
我还尝试连接类型Array
和GenTraversable
- 因为存在从Array
到WrapperArray <: 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)
}
然后隐含使其看起来像str
和print
是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)
答案 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)