2013-03-03 2 views
1

Скажем, у меня есть, например, двумерный массив, и я храню некоторые индексы в кортежах:Uncurrying/tupling многомерный массив в Scala?

val testArray = Array.ofDim[Double](3, 4) 
val ixs = (1,2) 

Я хотел бы использовать эти кортежи непосредственно, например, testArray(ixs). Однако Function.tupled(testedArray _) возвращает «_ должен следовать методу; не может следовать Array [Array [Double]]».

Это потому, что Array на самом деле не является подтипом Function3? Если да, то как обойти это ограничение? Должен ли я использовать implicits для расширения ArrayOps или чего-то подобного? В настоящее время я храню данные в Map в качестве обходного пути.

ответ

2

Массивы массивов не подвергаются специальной обработке; они просто массивы (что-то). Таким образом, нет специального способа доступа к ним через кортежи. Но, как вы предположили, вы можете создать такой способ.

Вы можете

implicit class ArrayOps2D[@specialized T](xss: Array[Array[T]]) { 
    def apply(ij: (Int, Int)) = xss(ij._1)(ij._2) 
    def apply(i: Int, j: Int) = xss(i)(j) 
    def update(ij: (Int, Int), t: T) { xss(ij._1)(ij._2) = t } 
    def update(i: Int, j: Int, t: T) { xss(i)(j) = t } 
} 

Вы могли бы подумать об этом

implicit class ArrayOps2D[T](val xss: Array[Array[T]]) extends AnyVal { 
    def apply(ij: (Int, Int)) = xss(ij._1)(ij._2) 
    def apply(i: Int, j: Int) = xss(i)(j) 
    def update(ij: (Int, Int), t: T) { xss(ij._1)(ij._2) = t } 
    def update(i: Int, j: Int, t: T) { xss(i)(j) = t } 
} 

, но это не работает, а на мой взгляд. Из-за ограничений реализации вы не можете специализировать AnyVal. Более того, первый, вероятно, лучше, если вы используете примитивы много, так как он избегает боксирования примитивов (и JVM может справиться с тем, чтобы избежать создания объектов, надеюсь), в то время как последний более эффективен, если у вас в большинстве случаев нет примитивов (например, строки), так как вы (формально) не создаете объект. Но в вашем примере используются примитивы.

В любом случае, если вы сделаете это, у вас будет бесшовная двухиндексная адресация с кортежами и парами аргументов (как я ее написал). Вы не можете использовать методы обновления полностью без проблем! Они будут работать в основном, но они не будут автоматически продвигать числовые типы. Поэтому, если у вас есть парные разряды, и вы пишете a(1,2) = 3, он не сработает, потому что он не найдет способ update(Int, Int, Int) и не думает использовать update(Int, Int, Double). Но вы можете исправить это самостоятельно, выполнив преобразование (или в этом случае напишите 3d).

+0

Благодарим за всестороннее обсуждение компромиссов между двумя подходами. –

+0

Кроме того, теперь вы можете (Scala 2.10+) «специализировать» AnyVal со значениями классов, хотя реализация по-разному, это не так [просто, как простое «подклассификация»] (http://docs.scala-lang.org/overviews/ ядро/стоимость classes.html). –

+0

@ TheTerribleSwiftTomato - Я не уверен, что вы имеете в виду. Фактически вы не можете использовать ключевое слово 'special' в 2.10, и я уже рассказываю об общей версии unboxed-array-boxed-elements в разделе« вы можете подумать ». –