简体   繁体   English

Scala构造函数中的可变参数

[英]variable parameters in Scala constructor

I would like to write a Matrix class in Scala from that I can instantiate objects like this: 我想在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.) )

I have tried this: 我已经试过了:

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

but then I get a type mismatch because the matrix rows are not of type List[Double]. 但是然后我得到了一个类型不匹配的信息,因为矩阵行的类型不是List [Double]。

Further it would be nice to just have to type Integers (1,2,3) instead of (1.,2.,3.) but still get a double matrix. 此外,最好只键入Integers(1,2,3)而不是(1.,2.,3。),但仍然得到一个双矩阵。

How to solve this? 如何解决呢?

Thanks! 谢谢! Malte 马尔特

(1.0, 2.0) is a Tuple2[Double, Double] not a List[Double] . (1.0, 2.0) Tuple2[Double, Double] (1.0, 2.0)Tuple2[Double, Double]而不是List[Double] Similarly (1.0, 2.0, 3.0) is a Tuple3[Double, Double, Double] . 同样(1.0, 2.0, 3.0) Tuple3[Double, Double, Double] (1.0, 2.0, 3.0)Tuple3[Double, Double, Double]

If you need to handle a fixed number of cardinality, the simplest solution in plain vanilla scala would be to have 如果您需要处理固定数量的基数,则普通香草scala中最简单的解决方案是

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

and so on. 等等。

Since there exist an implicit conversion from Int to Double , you can pass a tuple of ints and it will be automatically converted. 由于存在从IntDouble的隐式转换,您可以传递一个int的元组,它将被自动转换。

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

If you instead need to abstract over the row cardinality, enforcing an NxM using types, you would have to resort to some more complex solutions, perhaps using the shapeless library. 如果相反,您需要对行基数进行抽象,使用类型强制执行NxM ,则可能不得不采用一些更复杂的解决方案,也许使用无形库。

Or you can use an actual list, but you cannot restrict the cardinality, ie you cannot ensure that all rows have the same length (again, in vanilla scala, shapeless can help) 或者,您可以使用实际列表,但不能限制基数,即不能确保所有行的长度都相同(同样,在香草scala中,无形可以帮助您)

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

Finally, the 1. literal syntax is deprecated since scala 2.10 and removed in scala 2.11. 最后,从scala 2.10开始不推荐使用1.文字语法,并在scala 2.11中将其删除。 Use 1.0 instead. 请改用1.0

If you need support for very large matrices, consider using an existing implementation like Breeze . 如果需要大型矩阵的支持,请考虑使用Breeze之类的现有实现。 Breeze has a DenseMatrix which probably meets your requirements. Breeze的DenseMatrix可能符合您的要求。 For performance reasons, Breeze offloads more complex operations into native code. 由于性能原因,Breeze将更复杂的操作卸载到了本机代码中。

Getting Matrix algebra right is a difficult exercise and unless you are specifically implementing matrix to learn/assignment, better to go with proven libraries. 使矩阵代数正确是一项艰巨的任务,除非您专门实现矩阵来学习/分配,否则最好使用经过验证的库。

Edited based on comment below: 根据以下评论进行编辑:

You can consider the following design. 您可以考虑以下设计。

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

Usage: 用法:

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

You need to validate that all Rows are of the length and reject the input if they are not. 您需要验证所有行的长度,如果不是,则拒绝输入。

I have hacked a solution in an - I think - a bit unscala-ish way 我已经以一种-不可靠的方式破解了一个解决方案

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

works like

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

I don't really like it. 我不太喜欢 What do you think about it? 你怎么看待这件事?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM