2010-09-29 1 views
3

Je suis à mi-chemin à trouver une solution à ma question, mais j'ai le sentiment que ce ne sera pas très efficace. J'ai une structure cellulaire bidimensionnelle de tableaux de longueur variable qui est construite de manière non fonctionnelle dans Matlab que je voudrais convertir en Clojure. Voici un exemple de ce que je suis en train de faire:Quelle est la meilleure façon de traduire la génération d'un tableau de cellules multidimensionnel de 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; 

Mon plan actuel de mise en œuvre est d'utiliser 3 boucles où le premier est initialisé avec un vecteur de N vecteurs d'un vecteur vide. Chaque sous-boucle est initialisée par la boucle précédente. Je définis une fonction séparée qui prend le vecteur global et les sous-indices et la valeur et renvoie le vecteur avec un sous-vecteur mis à jour.

Il doit y avoir une façon plus intelligente d'utiliser 3 boucles/répétitions. Peut-être que certains réduisent la fonction qui simplifie la syntaxe en utilisant un accumulateur.

Répondre

2

Je ne suis pas 100% sûr que je comprends ce que votre code est en train de faire (je ne sais pas Matlab), mais cela pourrait être une approche pour la construction d'un vecteur multidimensionnel:

(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"]]] 

Cela ne fonctionne si indices allez dans le bon ordre (en augmentant), parce que vous ne pouvez pas conj ou assoc sur un vecteur n'importe où autre que l'un-passé-le-fin.

Je pense aussi qu'il serait acceptable d'utiliser make-array et de construire votre tableau via aset. C'est pourquoi Clojure offre un accès aux tableaux mutables Java; certains algorithmes sont beaucoup plus élégants de cette façon, et parfois vous en avez besoin pour la performance. Vous pouvez toujours vider les données dans des vecteurs Clojure après avoir terminé si vous voulez éviter les effets secondaires.

(je ne sais pas qui de ce ou l'autre version fonctionne mieux.)

(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? 
+0

Je ne suis pas Bien sûr, si je vais utiliser l'aset ou la version plus fonctionnelle ... mais j'imagine que le paramètre de tableau fonctionnel pourrait être transformé en une macro ou une fonction qui simplifie les choses. Merci. – Nick

1

Regardez à Incanter projet qui fournissent des routines pour le travail avec des ensembles de données, etc.

Questions connexes