7

Scalaで長方形の2次元(または多次元)配列データ構造をどのように表現しますか?

つまり、各行の長さは同じで、コンパイル時に検証されますが、ディメンションは実行時に決定されますか?

Seq[Seq[A]]は目的のインターフェイスを備えていますが、ユーザーが「不規則な」配列を提供できるため、実行時に障害が発生する可能性があります。

Seq[(A, A, A, A, A, A)](および同様の)長さが同じであることを確認しますが、コンパイル時にこの長さを指定することも強制します。

インターフェースの例

これが私が意味するインターフェースの例です(もちろん、内部ディメンションはタプルである必要はありません。リストまたは他のタイプとして指定できます):

// 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)
)))
4

3 に答える 3

6

これは、Shapelessライブラリのサイズ設定されたタイプを使用して可能です。

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

コンパイルしますfoo(a)が、コンパイルfoo(b)しません。

これにより、目的のインターフェイスに非常に近いものを作成できます。

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)
))
于 2012-07-17T07:19:41.720 に答える
2

適切なサイズを確保するためにカプセル化を使用します。

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 } 
}
于 2012-07-17T07:57:51.207 に答える
2

注:私は質問を読み間違え、長方形を正方形と間違えました。ああ、まあ、あなたが正方形を探しているなら、これは合うでしょう。それ以外の場合は、@TravisBrownの回答を使用する必要があります。

このソリューションは最も一般的なソリューションではないかもしれませんが、 Scalaでタプルクラスを定義する方法と一致しています。

class Rect[T] private (val data: Seq[T])

object Rect {
    def apply[T](a1: (T, T), a2: (T, T)) = new Rect(Seq(a1, a2))
    def apply[T](a1: (T, T, T), a2: (T, T, T), a3: (T, T, T)) = new Rect(Seq(a1, a2, a3))
    // Continued...
}

Rect(
     (1, 2, 3),
     (3, 4, 5),
     (5, 6, 7))

これはあなたが探していたインターフェースであり、無効なサイズの行、列、または要素のタイプがある場合、コンパイラーはあなたを停止します。

于 2012-07-18T07:15:27.967 に答える