Представление вашего массива на самом деле зависит от необходимости его использования, а не инициализации.Например, если у вас плотная матрица, вам, скорее всего, следует использовать вектор таких векторов:
[[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9],
[9, 8, 7, 6, 5],
[4, 3, 2, 1, 0],
[0, 1, 2, 3, 4]]
или один вектор с дополнительной информацией о необработанной длине:
{:length 5
:data
[0, 1, 2, 3, 4,
5, 6, 7, 8, 9,
9, 8, 7, 6, 5,
4, 3, 2, 1, 0,
0, 1, 2, 3, 4]
}
иесли вам нужна разреженная матрица, вы можете использовать hash-map
s:
{0 {0 0, 4 4},
2 {2 7},
3 {0 4, 2 2}}
(поскольку ваш 2D-массив мал и вы генерируете следующее значение на основе предыдущего, я считаю, что первый вариант лучше подходит для вас),
Если вы собираетесь выполнять множество специфических для матрицы манипуляций (умножение, декомпозиция и т. Д.), Вы можете использовать некоторые существующие библиотеки, такие как Incanter .
А что касается заполнения, я предлагаю использовать переходные процессы и сохранять промежуточные результаты, т.е. (для одномерного вектора):
(defn make-array [initial-value f length]
(loop [result (transient []), length-left length, interim-value initial-value]
(if (= length-left 0)
(persistent! result)
(recur (conj! result (f interim-value)) (- length-left 1) (f interim-value))))
Переходные процессы будут избегать созданияновая структура данных для каждого нового элемента, а промежуточное значение позволит избежать необходимости чтения предыдущего элемента из переходной структуры.