Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type-safe rectangular multidimensional array type

How do you represent a rectangular 2-dimensional (or multidimensional) array data structure in Scala?

That is, each row has the same length, verified at compile time, but the dimensions are determined at runtime?

Seq[Seq[A]] has the desired interface, but it permits the user to provide a "ragged" array, which can result in a run-time failure.

Seq[(A, A, A, A, A, A)] (and similar) does verify that the lengths are the same, but it also forces this length to be specified at compile time.

Example interface

Here's an example interface of what I mean (of course, the inner dimension doesn't have to be tuples; it could be specified as lists or some other type):

// Function that takes a rectangular array
def processArray(arr : RectArray2D[Int]) = {
    // do something that assumes all rows of RectArray are the same length
}

// Calling the function (OK)
println(processArray(RectArray2D(
    ( 0,  1,  2,  3),
    (10, 11, 12, 13),
    (20, 21, 22, 23)
)))
// Compile-time error
println(processArray(RectArray2D(
    ( 0,  1,  2,  3),
    (10, 11, 12),
    (20, 21, 22, 23, 24)
)))
like image 549
Mechanical snail Avatar asked Jul 17 '12 06:07

Mechanical snail


People also ask

What are the types of dimensional arrays?

There are mainly three types of the array: One Dimensional (1D) Array. Two Dimension (2D) Array. Multidimensional Array.

What is an example of a multidimensional array?

The total number of elements that can be stored in a multidimensional array can be calculated by multiplying the size of all the dimensions. For example: The array int x[10][20] can store total (10*20) = 200 elements. Similarly array int x[5][10][20] can store total (5*10*20) = 1000 elements.

Are there 3 dimensional arrays?

A 3D array is a multi-dimensional array(array of arrays). A 3D array is a collection of 2D arrays . It is specified by using three subscripts:Block size, row size and column size. More dimensions in an array means more data can be stored in that array.

What are multidimensional arrays?

Multidimensional arrays are an extension of 2-D matrices and use additional subscripts for indexing. A 3-D array, for example, uses three subscripts. The first two are just like a matrix, but the third dimension represents pages or sheets of elements.


2 Answers

This is possible using the Shapeless library's sized types:

import shapeless._

def foo[A, N <: Nat](rect: Seq[Sized[Seq[A], N]]) = rect

val a = Seq(Sized(1, 2, 3), Sized(4, 5, 6))
val b = Seq(Sized(1, 2, 3), Sized(4, 5))

Now foo(a) compiles, but foo(b) doesn't.

This allows us to write something very close to your desired interface:

case class RectArray2D[A, N <: Nat](rows: Sized[Seq[A], N]*)

def processArray(arr: RectArray2D[Int, _]) = {
  // Run-time confirmation of what we've verified at compile-time.
  require(arr.rows.map(_.size).distinct.size == 1)
  // Do something.
}

// Compiles and runs.
processArray(RectArray2D(
  Sized( 0,  1,  2,  3),
  Sized(10, 11, 12, 13),
  Sized(20, 21, 22, 23)
))

// Doesn't compile.
processArray(RectArray2D(
  Sized( 0,  1,  2,  3),
  Sized(10, 11, 12),
  Sized(20, 21, 22, 23)
))
like image 144
Travis Brown Avatar answered Oct 31 '22 21:10

Travis Brown


Using encapsulation to ensure proper size.

final class Matrix[T]( cols: Int, rows: Int ) {
  private val container: Array[Array[T]] = Array.ofDim[T]( cols, rows )
  def get( col: Int, row: Int ) = container(col)(row)
  def set( col: Int, row: Int )( value: T ) { container(col)(row) = value } 
}
like image 35
Neil Essy Avatar answered Oct 31 '22 21:10

Neil Essy