【问题标题】:variable parameters in Scala constructorScala构造函数中的可变参数
【发布时间】:2014-09-08 04:13:34
【问题描述】:

我想在 Scala 中编写一个 Matrix 类,我可以这样实例化对象:

val m1 = new Matrix( (1.,2.,3.),(4.,5.,6.),(7.,8.,9.) )

val m2 = new Matrix( (1.,2.,3.),(4.,5.,6.) )

val m3 = new Matrix( (1.,2.),(3.,4.) )

val m4 = new Matrix( (1.,2.),(3.,4.),(5.,6.) )

我试过这个:

class Matrix(a: (List[Double])* ) { }

然后我得到类型不匹配,因为矩阵行不是 List[Double] 类型。

此外,只需要输入整数 (1,2,3) 而不是 (1.,2.,3.) 但仍会得到一个双矩阵会很好。

如何解决?

谢谢! 马耳他

【问题讨论】:

    标签: scala


    【解决方案1】:

    (1.0, 2.0)Tuple2[Double, Double] 而不是 List[Double]。同样(1.0, 2.0, 3.0)Tuple3[Double, Double, Double]

    如果您需要处理固定数量的基数,在普通的 scala 中最简单的解决方案是拥有

    class Matrix2(rows: Tuple2[Double, Double]*)
    class Matrix3(rows: Tuple3[Double, Double, Double]*)
    

    等等。

    由于存在从IntDouble 的隐式转换,您可以传递一个整数元组,它将自动转换。

    new Matrix2((1, 2), (3, 4))
    

    如果您需要对行基数进行抽象,使用类型强制 NxM,您将不得不求助于一些更复杂的解决方案,可能使用 shapeless 库。

    或者你可以使用一个实际的列表,但你不能限制基数,即你不能确保所有的行都具有相同的长度(同样,在 vanilla scala 中,shapeless 可以提供帮助)

    class Matrix(rows: List[Double]*)
    new Matrix(List(1, 2), List(3, 4))
    

    最后,1. 文字语法自 scala 2.10 起已弃用,并在 scala 2.11 中删除。请改用1.0

    【讨论】:

    • 谢谢。但我想将该类用于大小为 n*m 的矩阵,其中 0
    • 和 new Matrix(List(1, 2), List(3, 4)) 太冗长了:(
    • 那么在这种情况下你肯定不能使用元组,因为它们在 scala 中最多可达 22 个。恐怕您将不得不使用列表,并注意这样您甚至不会强制所有行都具有相同的长度。
    【解决方案2】:

    如果您需要支持非常大的矩阵,请考虑使用现有的实现,例如 Breeze。 Breeze 有一个DenseMatrix,它可能满足您的要求。出于性能原因,Breeze 将更复杂的操作卸载到本机代码中。

    正确使用矩阵代数是一项困难的练习,除非您专门实施矩阵来学习/分配,否则最好使用经过验证的库。

    根据以下评论编辑:

    您可以考虑以下设计。

    class Row(n : Int*)
    class Matrix(rows: Row*) {...}
    

    用法:

    val m = new Matrix(Row(1, 2, 3), Row(2,3,4))
    

    您需要验证所有 Rows 的长度,如果不是,则拒绝输入。

    【讨论】:

    • 感谢您的建议。 Breeze 使用 DenseMatrix(rows: Int, cols: Int, data: Array[Double]) 之类的构造函数。我想创建一个类似于 Matlab 的库,对于只有一些编程技能的科学家来说,它很容易使用。它的用法应该像数学,而不是计算机科学。
    【解决方案3】:

    我以一种 - 我认为 - 有点不规范的方式破解了一个解决方案

    class Matrix(values: Object*) { // values is of type WrappedArray[Object]
      var arr : Array[Double] = null
      val rows : Integer = values.size
      var cols : Integer = 0
    
      var _arrIndex = 0
      for(row <- values) {
        // if Tuple (Tuple extends Product)
        if(row.isInstanceOf[Product]) {
          var colcount = row.asInstanceOf[Product].productIterator.length
          assert(colcount > 0, "empty row")
          assert(cols == 0 || colcount == cols, "varying number of columns")
          cols = colcount
    
          if(arr == null) {
            arr = new Array[Double](rows*cols)
          }
    
          for(el <- row.asInstanceOf[Product].productIterator) {
            var x : Double = 0.0
            if(el.isInstanceOf[Integer]) {
              x = el.asInstanceOf[Integer].toDouble
            }
            else {
              assert(el.isInstanceOf[Double], "unknown element type")
              x = el.asInstanceOf[Double]
            }
    
            arr(_arrIndex) = x
            _arrIndex = _arrIndex + 1
          }
        }
      }
    }
    

    object ScalaMatrix extends App {
      val m1 = new Matrix((1.0,2.0,3.0),(5,4,5))
      val m2 = new Matrix((9,8),(7,6))
      println(m1.toString())
      println(m2.toString())
    }
    

    我真的不喜欢它。你怎么看?

    【讨论】:

    • 它有点凌乱且远非实用,但最重要的是你仍然被限制在 22 个元素之内。
    • 是的,没错。我可以接受元组的 22 个元素限制,因为用户很可能只会输入小于 10x10 的矩阵。更大的矩阵将由代码创建 - 通过提供数据数组或通过设置行/列向量或单个元素。这仍然必须执行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-08
    • 2019-10-02
    • 1970-01-01
    • 2018-08-28
    • 2013-03-16
    • 2016-02-19
    • 1970-01-01
    相关资源
    最近更新 更多