2010-07-13 4 views
8

J'ai le problème suivant: J'ai une série chronologique avec plus de 10000 entrées et je veux effectuer quelques calculs avec chacun d'eux. Cela ne serait pas un problème à lui seul, mais je dois obtenir la dernière valeur calculée pour obtenir la suivante. Une forme très simple de ce que je besoin ressemblerait à ceci:problème itérer sur une série chronologique en clojure

Val(n) = Val(n-1) + (time-series-entry/2) (! Ou quelque chose comme ça)

Je n'ai aucune idée comment gérer cela. Il suffit de faire quelque chose comme ceci:

(defn calc-val 
    [time-series element] 
    (seq (cons (generate-val-element time-series element) 
      (calc-val time-series (inc element))))) 

ne fonctionnerait pas parce que ne peut pas (au moins je ne sais pas comment!) Obtenir la dernière valeur calculée. Puis j'ai pensé: OK, utilisons Loop-Recur. Cela me donnerait la valeur correspondant à l'entrée de la série temporelle MAIS pour la suivante je devrais refaire tous les calculs. Itérer serait la bonne chose, mais cela n'a pas fonctionné parce que la fonction a des effets secondaires.

Donc, je suis coincé ici sur celui-ci. Ce serait génial si quelqu'un pouvait me donner un indice.

Répondre

3

Si vous voulez juste un indice; regarder en utilisant partition.

Pour un peu plus d'un soupçon ...

(defn calc-val 
    [time-series element] 
    (let [p (partition 2 1 time-series)] 
    (for [t p] 
     (let [first-value (first t) 
      second-value (second t)] 
     (do whatever you need to here))))) 

Bien que cela n'a pas été testé, il devrait fonctionner ou être proche de travailler :)

Explication

(partition n i seq) sépare seq en parties que les listes de longueur n (2 dans ce cas) avec chevauchement i (1 dans ce cas), puis nous itérer sur ceux avec for, et faire ce que nous voulons avec les pièces.

+0

Si je comprendre la question correctement, le résultat de la transformation à chaque étape dépend du résultat de la transformation à l'étape précédente - pas sur l'entrée précédente non transformée. Donc indirectement cela dépend du fragment initial entier de la série seq qui le précède. (En espérant être corrigé par l'OP si je me trompe. :-)) –

+0

Si c'est le cas, absolument. Je l'ai compris différemment (comme son exemple impératif l'a fait croire autrement) mais je suis heureux d'avoir tort ou raison! De toute façon, il est entre de bonnes mains;) – Isaac

+0

Il me semble aussi. En espérant qu'il/elle accepte. :-) –

7

Si vous ne vous préoccupez le résultat final, utilisez reduce; si vous avez besoin pour obtenir un des résultats suivants de la transformation de chaque valeur à son tour (où chaque transformation dépend des précédents), utilisez reductions (dans clojure.contrib.seq-utils en 1.1 et en 1.2 clojure.core).

Ci-dessous, transform-first-entry fait tout ce que vous voulez faire à la première entrée (si vous n'avez pas besoin de le transformer en aucune façon, vous pouvez laisser le premier argument de reduce/reductions et utiliser entries plutôt que comme (rest entries l'argument final); transform-entry est la fonction qui prend le résultat de la transformation de l'entrée précédente et de l'entrée actuelle (dans cet ordre) et produit le résultat de la transformation pour l'entrée en cours.

;;; only care about the final result 
(reduce transform-entry 
     (transform-first-entry (first series)) 
     (rest entries)) 

;;; need to get a seq of intermediate results 
(reductions ...arguments as above...) 

Notez que reductions est paresseux.

En supposant que vous vouliez quitter la première entrée inchangé et appliquer votre exemple transformation du texte de la question aux entrées suivantes, vous pouvez utiliser

(defn transform-entry [prev-transformed current] 
    (+ prev-transformed 
    (/ current 2))) 

que la fonction de réduction de

(reduce transform-entry series) ; ...or reductions 
Questions connexes