I have multidimensional arrays where the dimensions are saved in an ArrayBuffer
.
When I print it, obviously, I get e.g. ArrayBuffer(2, 2, 3)
, but I would like to have 2x2x3
. I know that I can do it as follows println(multiarray.dim.mkString("x"))
.
Is there any "magical" way that I get 2x2x3
by simply issuing println(multiarray.dim)
?
EDIT
dim
is me开发者_运维技巧thod of the multidimensional arrays that gives the dimensions...
If dim
returns an ArrayBuffer, then, no, you can't just use println(multiarray.dim)
. Here are some simple alternatives though:
Define a method to return the dimensions as a String (in your multiarray class):
def dimStr = dim mkString "x"
Define a utility method for printing:
def printdim(buffer: ArrayBuffer[Int]) = println(buffer mkString "x") // or def printdim(multiarray: MultiArray) = println(multiarray.dim mkString "x")
Generalizing toString:
With a bit more effort, you can define a version of println
that will work the way you'd like. The idea is to abstract the String-creation logic. The power of this approach is that, once the basic infrastructure is in place, you're able to control the "stringification" of any type just by bringing an appropriate implicit into scope.
Start by defining a type class:
trait Stringable[T] extends (T => String)
Provide a default implementation of the type class (which just falls back on the ordinary toString
method):
class DefaultStringable[T] extends Stringable[T] {
def apply(x: T) = x.toString
}
object DefaultStringable {
implicit def any2stringable[T]: Stringable[T] = new DefaultStringable[T]
}
Implement the type class for your use case:
implicit object DimIsStringable extends Stringable[ArrayBuffer[Int]] {
def apply(buf: ArrayBuffer[Int]) = buf mkString "x"
}
Define a print method that uses the type class:
def myprintln[T](x: T)(implicit e: Stringable[T]) = e(x)
Fun.
import DefaultStringable._
myprintln(ArrayBuffer(1,2,3)) // prints "ArrayBuffer(1, 2, 3)"
Profit!
import DimIsStringable._
myprintln(ArrayBuffer(1,2,3)) // prints "1x2x3"
If desired, you can make the default type class always available without requiring any import. To do so, you provide the conversion in a companion module to the Stringable trait (as demonstrated below). The disadvantage of doing so is that you'll no longer have a compiler error to alert you if you forget to import an appropriate Stringable.
object Stringable {
implicit def any2stringable[T]: Stringable[T] = new DefaultStringable[T]
}
I m' not sure that would qualify as magical, but would that be ok?
class ArrayDim extends ArrayBufer[Int] {
override def toString = mkString ("x")
}
Edit :
Then in the code of your multidimensional array class,
replace dim = new ArrayBuffer
by dim = new ArrayDim
. Depending on how you fill the buffer, you may need minor changes in the code.
You can use an implicit conversion to something that has a dim method. Here's an example:
scala> implicit def toDim(t: Traversable[_]) = new { def dim = t.mkString("x") }
toDim: (t: Traversable[_])java.lang.Object{def dim: String}
scala> List(1, 2, 3).dim
res0: String = 1x2x3
scala> ArrayBuffer(2, 2, 3).dim
res1: String = 2x2x3
You can define println locally, overriding the imported defintion, if you wish:
def println(a : Any) = System.out.println(a match {
case seq : Seq[_] => seq.mkString("x")
case a@_ => a
}
println(scala.collection.mutable.ArrayBuffer(1,2,3)) // yields 1x2x3
println("Hello") //yields "Hello"
Unfortunately this won't condition on the type of variable inside the Seq. There might be a way to do that, though I'm not sure since we can't require that a has a Manifest. Will have a think.
精彩评论