4
$\begingroup$

Suppose as is a list of associations that I want to update. For example:

as = Table[<|"f1"->i,"f2"->2,"f3"->3|>,{i,3}];  (*original*)
as = Append[#,{"f1"->0,"f2"->#f1+10}]& /@ as    (*update*)

Question: Is this a speedy approach to updating? If not, what are better approaches?

E.g., can it be preferable to change as in place, and if so how? (I care more about speed than memory. At the moment, I don't want to convert to a Dataset.)

$\endgroup$
  • $\begingroup$ How large is your Association, and how many of its values are you updating? And have you seen AssociateTo? $\endgroup$ – Mr.Wizard Oct 29 '18 at 17:16
  • $\begingroup$ @Mr.Wizard I know about AssociateTo but (since it has HoldFirst) did not see a useful way to exploit it. The lists of associations are short, but I have to do this many times. Aside from that, I am interested in the answer more generally. The only in-place alternatives I have tried use explicit loops and assignment. For example, Do[as[[i, "f2"]] = as[[i, "f1"]] + 10; as[[i, "f1"]] = 0;, {i, Length[as]}]. Of course, this is much slower. $\endgroup$ – Alan Oct 29 '18 at 18:05
5
$\begingroup$

Another possibility:

as = Table[<|"f1"->i,"f2"->2,"f3"->3|>,{i,3}];
as[[All, "f2"]] = as[[All, "f1"]] + 10;
as[[All, "f1"]] = 0;

as

{<|"f1" -> 0, "f2" -> 11, "f3" -> 3|>, <|"f1" -> 0, "f2" -> 12, "f3" -> 3|>, <|"f1" -> 0, "f2" -> 13, "f3" -> 3|>}

Speed comparison:

as = Table[<|"f1"->i,"f2"->2,"f3"->3|>, {i, 10^6}];
as = Append[#,{"f1"->0,"f2"->#f1+10}]& /@ as; //AbsoluteTiming

bs = Table[<|"f1"->i,"f2"->2,"f3"->3|>, {i, 10^6}];
bs[[All, "f2"]] = bs[[All, "f1"]] + 10; //AbsoluteTiming
bs[[All, "f1"]] = 0; //AbsoluteTiming

Normal[KeySort /@ as] == Normal[KeySort /@ bs]

{3.00381, Null}

{0.806365, Null}

{0.612295, Null}

True

$\endgroup$
3
$\begingroup$

OP reports that AssociateTo[as[[i]], . . .] no longer works in version 11.3.0


I don't follow the reticence to use AssociateTo you expressed in a comment above. It seems expressly suited to this purpose, e.g.:

big = AssociationMap[#^2 &, Range@1*^6];
new = # -> #^3 & /@ Array[Prime, 1000];
AssociateTo[big, new]; // AbsoluteTiming

big[[71]]
71^3
{0.00223797, Null}

357911

357911

Can you show me a problem with this?


Carl Woll objects that I did not address the list-of-associations in your example. Indeed, but as AssociateTo works on Part one can iterate like this:

as = Table[<|"f1" -> i, "f2" -> 2, "f3" -> 3|>, {i, 3}];(*original*)

Do[
 AssociateTo[as[[i]], {"f1" -> 0, "f2" -> as[[i, "f1"]] + 10}],
 {i, Length@as}
]

as
{<|"f1" -> 0, "f2" -> 11, "f3" -> 3|>,
 <|"f1" -> 0, "f2" -> 12, "f3" -> 3|>,
 <|"f1" -> 0, "f2" -> 13, "f3" -> 3|>}
$\endgroup$
  • $\begingroup$ The OP has a list of associations, while I think you have a single association. $\endgroup$ – Carl Woll Oct 29 '18 at 18:15
  • 1
    $\begingroup$ In 11.3.0, you cannot use AssociateTo with Part like this. (This was the thrust of my comment above.) What version are you using? (And what is the timing?) $\endgroup$ – Alan Oct 29 '18 at 18:41
  • $\begingroup$ @Alan Odd, and a little disappointing! I am using version 10.1. $\endgroup$ – Mr.Wizard Oct 29 '18 at 18:45
  • $\begingroup$ @Alan I have made a note of this incompatibility at the top of my answer. Since I do not have access to the latest versions I think I should let someone that does attempt to answer this now. $\endgroup$ – Mr.Wizard Oct 29 '18 at 19:07
  • 2
    $\begingroup$ Your Do loop works just fine with a simple tweak: Do[ With[{i = i}, AssociateTo[ as[[i]], ...] ], {i, Length@as}] $\endgroup$ – Jason B. Oct 29 '18 at 20:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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