0

I want to tile a small array multiple times in a large array. I'm looking for an "official" way of doing this. A naive solution follows:

val arr = Array[Int](1, 2, 3)
val array = {
  val arrBuf = ArrayBuffer[Int]()
  for (_ <- 1 until 10) {
    arrBuf ++= arr
  }
  arrBuf.toArray
}
2
  • Any reason for using Arrays instead of a proper collection? Arrays are used only on performance-sensitive situations; and as such, the answer Andronicus is not really a good idea due to the performance overhead. But it may be an elegant solution for Lists or Vectors. Commented Jun 5, 2020 at 3:13
  • Cool. Can you elaborate on that? Why arrays help increase performance and why the solution, albeit being very short might slow the execution? Thanks Commented Jun 5, 2020 at 3:17

2 Answers 2

2

If you do not know why Arrays are good for performance (meaning you do not really need raw performance in this case) I would recommend you do not use them, and rather stick with List or Vector instead.

Arrays are not proper Scala collections, they are just plain JVM arrays. Meaning, they are mutable, very efficient (especially for unboxed primitives), fixed in memory size, and very restricted. They behave like normal scala collections because of implicit conversions and extension methods. But, due to their mutability and invariance, you really should avoid them unless you have good reasons for using them.
The proposed solution by Andronicus is not ideal for arrays (but it would be a very good solution for any real collection) because given arrays have fixed memory size, this fattening will end in constant reallocations and memory copying under the hood.

Anyways, here is a slight variation to such solution, using lists instead; which is a little bit more efficient.

implicit class ListOps[A](private val list: List[A]) extends AnyVal {
  def times[B >: A](n: Int): List[B] =
    Iterator.fill(n)(list).flatten.toList
}

List(1, 2, 3).times(3)
// res: List[Int] = List(1, 2, 3, 1, 2, 3, 1, 2, 3)

And here is also an efficient version using the new ArraySeq introduced in 2.13; which is an immutable Array.
(Note, you can do this using plain Arrays too)

implicit class ArraySeqOps[A](private val arr: ArraySeq[A]) extends AnyVal {
  def times[B >: A](n: Int): ArraySeq[B] =
    ArraySeq.tabulate(n * arr.lenght) { i => arr(i % arr.length) }
}

ArraySeq(1, 2, 3).times(3)
// res: ArraySeq[Int] = ArraySeq(1, 2, 3, 1, 2, 3, 1, 2, 3)
Sign up to request clarification or add additional context in comments.

Comments

1

You can use Array.fill:

Array.fill(10)(Array(1, 2, 3)).flatten

3 Comments

The result is Array(Array(1, 2, 3), Array(1, 2, 3), ..., Array(1, 2, 3))
The result is Array(Array(1, 2, 3), Array(1, 2, 3), ..., Array(1, 2, 3)). But you remind me of flatMap though. I could use val arr: Array[Int] = Array.fill(10)(Array(1, 2, 3)) flatMap {v: Array[Int] => v}
@YanqiHuang; You don't need flatMap(), just add .flatten at the end.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.