Как лучше всего перевести генерацию многомерного массива ячеек из Matlab в Clojure? - PullRequest
3 голосов
/ 29 сентября 2010

Я на полпути в поиске решения моего вопроса, но у меня есть ощущение, что оно не будет очень эффективным.У меня есть двумерная структура ячеек массивов переменной длины, которая в Matlab построена очень не функционально, и я бы хотел преобразовать ее в Clojure.Вот пример того, что я пытаюсь сделать:

pre = cell(N,1);
aux = cell(N,1);
for i=1:Ne
  for j=1:D
    for k=1:length(delays{i,j})
        pre{post(i, delays{i, j}(k))}(end+1) = N*(delays{i, j}(k)-1)+i;
        aux{post(i, delays{i, j}(k))}(end+1) = N*(D-1-j)+i; % takes into account delay
    end;
  end;
end;

Мой текущий план реализации состоит в том, чтобы использовать 3 цикла, где первый инициализируется вектором из N векторов пустого вектора.Каждый подчиненный цикл инициализируется предыдущим циклом.Я определяю отдельную функцию, которая принимает общий вектор, подиндексы и значение и возвращает вектор с обновленным субвектором.

Должен быть более разумный способ сделать это, чем использование 3 цикла / рекурсоров.Возможно, некоторая функция сокращения, которая упрощает синтаксис с помощью аккумулятора.

Ответы [ 2 ]

2 голосов
/ 29 сентября 2010

Я не уверен на 100%, что понимаю, что делает ваш код (я не знаю Matlab), но это может быть одним из подходов для построения многомерного вектора:

(defn conj-in
  "Based on clojure.core/assoc-in, but with vectors instead of maps."
  [coll [k & ks] v]
  (if ks
    (assoc coll k (conj-in (get coll k []) ks v))
    (assoc coll k v)))

(defn foo []
  (let [w 5, h 4, d 3
        indices (for [i (range w)
                      j (range h)
                      k (range d)]
                  [i j k])]
    (reduce (fn [acc [i j k :as index]]
              (conj-in acc index
                       ;; do real work here
                       (str i j k)))
            [] indices)))

user> (pprint (foo))
[[["000" "001" "002"]
  ["010" "011" "012"]
  ["020" "021" "022"]
  ["030" "031" "032"]]
 [["100" "101" "102"]
  ["110" "111" "112"]
  ["120" "121" "122"]
  ["130" "131" "132"]]
 [["200" "201" "202"]
  ["210" "211" "212"]
  ["220" "221" "222"]
  ["230" "231" "232"]]
 [["300" "301" "302"]
  ["310" "311" "312"]
  ["320" "321" "322"]
  ["330" "331" "332"]]
 [["400" "401" "402"]
  ["410" "411" "412"]
  ["420" "421" "422"]
  ["430" "431" "432"]]]

Это работает только в том случае, если indices идет в правильном порядке (увеличивается), потому что вы не можете conj или assoc на векторе где-либо, кроме одного за другим.

Я также думаю, что было бы приемлемо использовать make-array и построить ваш массив с помощью aset. Вот почему Clojure предлагает доступ к изменяемым массивам Java; некоторые алгоритмы намного более элегантны, и иногда они нужны вам для производительности. Вы можете всегда выгружать данные в векторы Clojure после того, как закончите, если хотите избежать побочных эффектов.

(я не знаю, какая из этой или другой версии работает лучше.)

(defn bar []
  (let [w 5, h 4, d 3
        arr (make-array String w h d)]
    (doseq [i (range w)
            j (range h)
            k (range d)]
      (aset arr i j k (str i j k)))
    (vec (map #(vec (map vec %)) arr))))  ;yikes?
1 голос
/ 29 сентября 2010

Посмотрите на Incanter проект, который предоставляет подпрограммы для работы с наборами данных и т. Д.

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