7
$\begingroup$

Suppose I have an association where keys are dates, and values are returns of some portfolio, and I want to convert the returns to cumulative returns. Now, this can be done as follows:

Association[
    Module[ {porfolio = KeySort[port]},
        MapThread[Rule, {Keys[porfolio], Exp[FoldList[Plus, Values[portfolio]]]}]
    ]
]

But this seems clunky. Is there some more elegant way of achieving the aim?

$\endgroup$
7
  • $\begingroup$ Can you post a short example of port? $\endgroup$
    – Stitch
    Mar 29, 2017 at 21:54
  • $\begingroup$ @Stitch Sure, here is a not-so-short example: dropbox.com/s/og07v3l8e020c3w/egport.m?dl=0 $\endgroup$
    – Igor Rivin
    Mar 29, 2017 at 22:28
  • $\begingroup$ Does anyone know why Accumulate[ <|"a" -> 1, "b" -> 2, "c" -> 3|> ] doesn't work? I thought this kind of thing was missing from version 10 simply because there wasn't time to add it, but it still doesn't work in version 11.1. $\endgroup$
    – Mr.Wizard
    Mar 30, 2017 at 2:24
  • $\begingroup$ @Mr.Wizard Would that no be because the internal ordering of the association has nothing to do a priori with what you type in, and thus it is not clear what order you are accumulating in? Just a thought... $\endgroup$
    – Igor Rivin
    Mar 30, 2017 at 4:14
  • 1
    $\begingroup$ @Mr. Wizard, on a Dataset[] without named rows, I can see Accumulate[] working on it. Otherwise... $\endgroup$ Mar 30, 2017 at 5:49

4 Answers 4

7
$\begingroup$

Best I can tell you really just want AssociationThread. It circumvents the Association and the MapThread.

p = AssociationThread[Range[100], Range[100]];
AssociationThread[Keys@p, N@Exp[FoldList[Plus, Values[p]]]]

That does what you were doing before in a few fewer calls. Also note that Associations support lots of functional programming stuff. KeyMap and Map exist of course and KeyValueMap is there too.

If you're wondering why FoldList doesn't do this natively consider that Fold andFoldList are supposed to be direct counter-parts. FoldList could return an Association with the keys realigned, but that wouldn't make sense with Fold. So there's no way to make an intuitive, compatible definition across both of them. And so best to one for neither of them. With AssociationThread rebuilding your association is trivial anyway, so I think they didn't really see the need either.

$\endgroup$
8
  • $\begingroup$ There is a problem with this (which I pointed out in one of my comments to another answer) is that the ordering of keys in an association is (intentionally) non-deterministic, so one pretty much has to do a KeySort before this has any semantic content... Still, I had no idea AssociationThread existed! $\endgroup$
    – Igor Rivin
    Mar 30, 2017 at 0:07
  • 1
    $\begingroup$ @IgorRivin Yes and no. It's like a hash-map with ordering. So it can be indexed just like a list. If you want something with keys ordered according to their hash values you can check out the internal System`Private`HashTable. Never figured out exactly how it works, so if you do post a Q&A type question on it for me to upvote. $\endgroup$
    – b3m2a1
    Mar 30, 2017 at 0:14
  • $\begingroup$ I am guessing that the ordering depends on the hashing algorithm, which is not guaranteed to remain whatever it is today... $\endgroup$
    – Igor Rivin
    Mar 30, 2017 at 0:18
  • $\begingroup$ @IgorRivin Of course not. But few top-level structures (none I can currently think of) will impose an ordering on their equivalent of the hash table keys. You'll probably have to go internal if you want that. $\endgroup$
    – b3m2a1
    Mar 30, 2017 at 0:20
  • 1
    $\begingroup$ The documentation states that Sort and KeySort can be applied to associations to produce well-ordered associations. Furthermore, associations are documented to support numeric part indices and value updating from ordered lists. From these assertions, we must conclude that association element order is being actively preserved independently of the key representation (e.g. like Java's LinkedHashMap). Still, it would be nice if the documentation explicitly stated that association maintain their order rather than just these implicit statements. $\endgroup$
    – WReach
    Mar 30, 2017 at 5:49
6
$\begingroup$

The shortest (and faster) way is to use Accumulate with pre-computed sorted Association:

eg = <|"2012-08-29" -> -0.2, "2012-08-30" -> 0.2, 
   "2012-08-31" -> -0.05, "2012-09-04" -> 0.05, "2012-09-05" -> -0.5, 
   "2012-09-01" -> -0.2, "2012-09-07" -> -0.3, "2012-09-10" -> 0.9|>;
egs = KeySort@eg;
AssociationThread[Keys@egs, egs // Values // Accumulate // Exp]

<|"2012-08-29" -> 0.818731, "2012-08-30" -> 1., "2012-08-31" -> 0.951229, "2012-09-01" -> 0.778801, "2012-09-04" -> 0.818731, "2012-09-05" -> 0.496585, "2012-09-07" -> 0.367879, "2012-09-10" -> 0.904837|>

$\endgroup$
2
  • 1
    $\begingroup$ That is a good way, though (to play devil's advocate :)) it ONLY works with Plus as the thing being accumulated... $\endgroup$
    – Igor Rivin
    Mar 30, 2017 at 1:58
  • 1
    $\begingroup$ @IgorRivin Well, you know, they say there is a function for everything in MMA :) $\endgroup$
    – Stitch
    Mar 30, 2017 at 2:00
6
$\begingroup$

These are not functional solutions, but they are fairly concise owing to the "transparency" of associations to operators like Map and Exp:

Module[{t = 0}, Map[t += # &, eg]] // Exp

or Set:

Module[{e = eg}, e[[All]] = e // Values // Accumulate // Exp; e]

These solutions assume that the association eg is already in the desired order (like the file linked in the question -- use KeySort@eg if necessary).

$\endgroup$
3
$\begingroup$

You could write a version of FoldList that works on Associations:

foldList[f_, assoc_Association] := 
    MapThread[Rule, {Keys@assoc, FoldList[f, Values@assoc]}] // Association

Then you can simply do

Exp /@ foldList[ Plus, KeySort@port ]
$\endgroup$
5
  • $\begingroup$ True, but the principle is still the same, and the whole disassembling-reassembling process seems inelegant... $\endgroup$
    – Igor Rivin
    Mar 29, 2017 at 22:29
  • $\begingroup$ @Igor Absent something built in, I think one has to choose between disassembling-reassembling or for-loop-style iteration. $\endgroup$
    – jjc385
    Mar 29, 2017 at 22:33
  • $\begingroup$ @Igor Aside from that issue, are you hoping for something more elegant? I find it hard to imagine something more elegant than a FoldList-like solution. $\endgroup$
    – jjc385
    Mar 29, 2017 at 22:36
  • 2
    $\begingroup$ I agree, but it is not obvious that something is not built in (Associations support some, but not all, list operations, so it seems a little underbaked, so maybe more baking had occurred while we were not looking?!) $\endgroup$
    – Igor Rivin
    Mar 29, 2017 at 22:36
  • 1
    $\begingroup$ I guess part of the point is that there is no canonical order on the keys of an association, so things like Fold don't a a priori make sense, so maybe you are right - this maybe the best one can hope for... $\endgroup$
    – Igor Rivin
    Mar 29, 2017 at 22:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.