63

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!

Seth Tisue
  • 29,985
  • 11
  • 82
  • 149
Ivan Longin
  • 3,207
  • 4
  • 33
  • 42
  • Try similar code in Java and you'll see that it does the same thing. `T[].toString()` does not return a `String` containing the elements of the array. – Jashaszun Jul 13 '13 at 21:37
  • 1
    I am bit of rusty in java :D ... so, you are saying that there is no solution for printing array but writing function myself? ... – Ivan Longin Jul 13 '13 at 21:42
  • dupe of http://stackoverflow.com/questions/3328085/scala-printing-arrays and others – Seth Tisue Jul 13 '13 at 22:33
  • @SethTisue You're right, kind of a dupe, except in this case it's *driving him crazy*. Not sure anyone solved that part. I noticed that when you fixed the typo, you neglected to change var to val. BTW. – som-snytt Jul 14 '13 at 19:25
  • @som-snytt: nitpicker's nits picked! – Seth Tisue Jul 15 '13 at 15:26

7 Answers7

111

mkString will convert collections (including Array) element-by-element to string representations.

println(a.mkString(" "))

is probably what you want.

Rex Kerr
  • 166,841
  • 26
  • 322
  • 407
18

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
som-snytt
  • 39,429
  • 2
  • 47
  • 129
14

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(""))
Haimei
  • 12,577
  • 3
  • 50
  • 36
4

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)
Jiri Kremser
  • 12,471
  • 7
  • 45
  • 72
3

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

James Lawson
  • 8,150
  • 48
  • 47
2

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))
Yuichiroh
  • 181
  • 1
  • 5
1

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)         
DaoWen
  • 32,589
  • 6
  • 74
  • 101