Printing array in Scala
ArraysScalaArrays Problem Overview
I am having problem with most basic Scala operation and it is making me crazy.
val a = Array(1,2,3)
println(a) and result is [I@1e76345
println(a.toString()) and result is [I@1e76345
println(a.toString) and result is [I@1e76345
Can anyone tell me how to print array without writing my own function for doing that because that is silly. Thanks!
Arrays Solutions
Solution 1 - Arrays
mkString
will convert collections (including Array
) element-by-element to string representations.
println(a.mkString(" "))
is probably what you want.
Solution 2 - Arrays
You can do the normal thing (see either Rex's or Jiri's answer), or you can:
scala> Array("bob","sue")
res0: Array[String] = Array(bob, sue)
Hey, no fair! The REPL printed it out real nice.
scala> res0.toString
res1: String = [Ljava.lang.String;@63c58252
No joy, until:
scala> runtime.ScalaRunTime.stringOf(res0)
res2: String = Array(bob, sue)
scala> runtime.ScalaRunTime.replStringOf(res0, res0.length)
res3: String =
"Array(bob, sue)
"
scala> runtime.ScalaRunTime.replStringOf(res0, 1)
res4: String =
"Array(bob)
"
I wonder if there's a width setting in the REPL. Update: there isn't. It's fixed at
val maxStringElements = 1000 // no need to mkString billions of elements
But I won't try billions:
scala> Array.tabulate(100)(identity)
res5: Array[Int] = Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99)
scala> import runtime.ScalaRunTime.replStringOf
import runtime.ScalaRunTime.replStringOf
scala> replStringOf(res5, 10)
res6: String =
"Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
"
scala> res5.take(10).mkString(", ")
res7: String = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Wait, let's make that:
scala> res5.take(10).mkString("Array(", ", ", ")")
res8: String = Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
This might be obvious:
scala> var vs = List("1")
vs: List[String] = List(1)
scala> vs = null
vs: List[String] = null
scala> vs.mkString
java.lang.NullPointerException
So instead:
scala> import runtime.ScalaRunTime.stringOf
import runtime.ScalaRunTime.stringOf
scala> stringOf(vs)
res16: String = null
Also, an array doesn't need to be deep to benefit from its stringPrefix:
scala> println(res0.deep.toString)
Array(bob, sue)
Whichever method you prefer, you can wrap it up:
implicit class MkLines(val t: TraversableOnce[_]) extends AnyVal {
def mkLines: String = t.mkString("", EOL, EOL)
def mkLines(header: String, indented: Boolean = false, embraced: Boolean = false): String = {
val space = "\u0020"
val sep = if (indented) EOL + space * 2 else EOL
val (lbrace, rbrace) = if (embraced) (space + "{", EOL + "}") else ("", "")
t.mkString(header + lbrace + sep, sep, rbrace + EOL)
}
}
But arrays will need a special conversion because you don't get the ArrayOps:
implicit class MkArrayLines(val a: Array[_]) extends AnyVal {
def asTO: TraversableOnce[_] = a
def mkLines: String = asTO.mkLines
def mkLines(header: String = "Array", indented: Boolean = false, embraced: Boolean = false): String =
asTO.mkLines(header, indented, embraced)
}
scala> Console println Array("bob","sue","zeke").mkLines(indented = true)
Array
bob
sue
zeke
Solution 3 - Arrays
Here are two methods.
One is to use foreach:
val a = Array(1,2,3)
a.foreach(println)
The other is to use mkString:
val a = Array(1,2,3)
println(a.mkString(""))
Solution 4 - Arrays
If you use list instead, toString()
method prints the actual elenents (not the hashCode)
var a = List(1,2,3)
println(a)
or
var a = Array(1,2,3)
println(a.toList)
Solution 5 - Arrays
For a simple Array of Ints like this, we can convert to a Scala List (scala.collection.immutable.List
) and then use List.toString()
:
var xs = Array(3,5,9,10,2,1)
println(xs.toList.toString)
// => List(3, 5, 9, 10, 2, 1)
println(xs.toList)
// => List(3, 5, 9, 10, 2, 1)
If you can convert to a List earlier and do all your operations with Lists, then you'll probably end up writing more idiomatic Scala, written in a functional style.
Note that using List.fromArray
is deprecated (and has been removed in 2.12.2) .
Solution 6 - Arrays
The method deep
in ArrayLike
recursively converts multidimensional arrays to WrappedArray
, and overwrites a long prefix "WrappedArray" with "Array".
def deep: scala.collection.IndexedSeq[Any] = new scala.collection.AbstractSeq[Any] with scala.collection.IndexedSeq[Any] {
def length = self.length
def apply(idx: Int): Any = self.apply(idx) match {
case x: AnyRef if x.getClass.isArray => WrappedArray.make(x).deep
case x => x
}
override def stringPrefix = "Array"
}
Usage:
scala> val arr = Array(Array(1,2,3),Array(4,5,6))
arr: Array[Array[Int]] = Array(Array(1, 2, 3), Array(4, 5, 6))
scala> println(arr.deep)
Array(Array(1, 2, 3), Array(4, 5, 6))
Solution 7 - Arrays
Rather than manually specifying all the parameters for mkString
yourself (which is a bit more verbose if you want to add start and end markers in addition to the delimiter) you can take advantage of the WrappedArray
class, which uses mkString
internally. Unlike converting the array to a List
or some other data structure, the WrappedArray
class just wraps an array reference, it's created in effectively constant time.
scala> val a = Array.range(1, 10)
a: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> println(a)
[I@64a2e69d
scala> println(x: Seq[_]) // implicit
WrappedArray(a, b, c, d)
scala> println(a.toSeq) // explicit
WrappedArray(1, 2, 3, 4, 5, 6, 7, 8, 9)