Array.isDefinedAt для n-мерных массивов в scala
Есть ли элегантный способ выразить
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))
}
в scala?
Ответы
Ответ 1
Я рекомендую не использовать массивы массивов для 2D-массивов по трем основным причинам. Во-первых, это допускает несогласованность: не все столбцы (или строки, выберите) должны быть одного размера. Во-вторых, это неэффективно - вам нужно следовать двум указателям вместо одного. В-третьих, существует очень мало библиотечных функций, которые прозрачно и полезно работают на массивах массивов в виде 2D-массивов.
Учитывая эти вещи, вы должны либо использовать библиотеку, которая поддерживает 2D-массивы, например scalala, или вы должны написать свой собственный. Если вы делаете последнее, между прочим, эта проблема волшебно уходит.
Итак, с точки зрения элегантности: нет, нет способа. Но кроме того, путь, который вы начинаете, содержит много неэффективности; вы, вероятно, сделаете все возможное, чтобы быстро уйти от него.
Ответ 2
Вам просто нужно проверить массив с индексом i
с помощью isDefinedAt
, если он существует:
def do_to_elt(i:Int, j:Int): Unit =
if (a.isDefinedAt(i) && a(i).isDefinedAt(j)) f(a(i)(j))
EDIT: пропустил эту часть об элегантном решении, поскольку я сосредоточился на ошибке в коде перед редактированием.
Относительно элегантности: нет, само по себе нет способа выразить это более элегантным способом. Некоторые могут сказать вам использовать шаблон 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
, а выполнять проверки достоверности в зависимости от длины массивов.)