Array.isDefinedAt для n-мерных массивов в scala - PullRequest
5 голосов
/ 23 мая 2011

Есть ли элегантный способ выразить

val a = Array.fill(2,10) {1}
def do_to_elt(i:Int,j:Int) {
    if (a.isDefinedAt(i) && a(i).isDefinedAt(j)) f(a(i)(j))
}

в скале?

Ответы [ 2 ]

1 голос
/ 23 мая 2011

Я рекомендую не использовать массивы массивов для 2D-массивов по трем основным причинам.Во-первых, это допускает несогласованность: не все столбцы (или строки, выбирайте сами) должны быть одинакового размера.Во-вторых, это неэффективно - вы должны следовать двум указателям вместо одного.В-третьих, существует очень мало библиотечных функций, которые прозрачно и полезно работают с массивами массивов как 2D-массивами.

Учитывая эти вещи, вы должны либо использовать библиотеку, которая поддерживает 2D-массивы, например scalala ,или вы должны написать свой собственный.Если вы сделаете последнее, среди прочего, эта проблема волшебным образом исчезнет.

Итак, с точки зрения элегантности: нет, пути нет.Но помимо этого, путь, по которому вы начинаете, содержит лотов неэлеганса;Вы, вероятно, сделаете все возможное, чтобы быстро сойти с него.

1 голос
/ 23 мая 2011

Вам просто нужно проверить массив по индексу i с isDefinedAt, если он существует:

def do_to_elt(i:Int, j:Int): Unit =
  if (a.isDefinedAt(i) && a(i).isDefinedAt(j)) f(a(i)(j))

РЕДАКТИРОВАТЬ: Пропустил ту часть об элегантном решении, как я сосредоточилсяоб ошибке в коде перед редактированием.

По поводу элегантности: нет, по сути, нет способа выразить это более элегантным способом.Некоторые могут посоветовать вам использовать pimp-my-library -Pattern, чтобы он выглядел более элегантно, но на самом деле это не так.

Если ваш единственный вариант использования - выполнитьфункция с элементом многомерного массива, когда индексы действительны, тогда этот код делает это, и вы должны его использовать.Вы можете обобщить метод, изменив сигнатуру для функции, применяемой к элементу, и, возможно, значение, если индексы недопустимы, например:

def do_to_elt[A](i: Int, j: Int)(f: Int => A, g: => A = ()) = 
  if (a.isDefinedAt(i) && a(i).isDefinedAt(j)) f(a(i)(j)) else g

, но я бы не стал ничего менять.Это также не выглядит более элегантно, но расширяет ваш вариант использования.

(Также: если вы работаете с массивами, вы в основном делаете это из соображений производительности, и в этом случае может быть даже лучше не использоватьisDefinedAt, но выполнять проверки достоверности на основе длины массивов.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...