10
$\begingroup$

I have the following Association:

as = <|{5, 2, 1} -> 3, {6, 1, 4} -> 9, {5, 1, 9} -> 12, {5, 2, 4} -> 6, {6, 2, 8} -> 10|>;

I want to total the values on the right side of the rules according to the middle values of the keys to get

<|2 -> 19, 1 -> 21|>

The only way I know how to do this is to transform the Association to a List:

li = as /. (Association | Rule) -> List

{{{5, 2, 1}, 3}, {{6, 1, 4}, 9}, {{5, 1, 9}, 12}, {{5, 2, 4}, 6}, {{6, 2, 8}, 10}}

li = GatherBy[li /. {{_, a_, _}, b_} :> {a, b}, First]

{{{2, 3}, {2, 6}, {2, 10}}, {{1, 9}, {1, 12}}}

Association @ MapThread[Rule, {Map[#[[1, 1]] &, li], Total /@ Map[Last, li, {2}]}]

<|2 -> 19, 1 -> 21|>

Is there a way to get this result without destroying the Association ?

$\endgroup$
13
$\begingroup$

Solutions based on GroupBy can be made a bit simpler by exploiting the fact that as itself can be used as a function, and I like the aesthetics of the curried form of Extract, where Extract[{2}] is equivalent to Extract[#, {2}]&:

In[1]:= GroupBy[Keys[as], Extract[{2}] -> as, Total]
Out[1]= <|2 -> 19, 1 -> 21|>
$\endgroup$
  • $\begingroup$ Impressive! How does the ` Extract[{2}] -> as` work? $\endgroup$ – eldo Oct 31 '15 at 19:00
  • 3
    $\begingroup$ First Keys gets all the keys from as, then you can Extract the second element from each key. This gives you the association <|2 -> {{5, 2, 1}, {5, 2, 4}, {6, 2, 8}}, 1 -> {{6, 1, 4}, {5, 1, 9}}|>, where GroupBy has already collected all the keys that share a common second element. The →as part effectively tells GroupBy to go back to the original association and treat the collected lists as keys (again), replacing {5,2,1} with 3, {6,1,4} with 9 and so on. $\endgroup$ – Graumagier Oct 31 '15 at 21:15
3
$\begingroup$

How about:

GroupBy[KeyValueMap[#[[2]] -> #2 &, as], First -> Last, Total]

<|2 -> 19, 1 -> 21|>

Or shorter, per @Kuba:

Merge[Total]@KeyValueMap[#[[2]] -> #2 &, as]
$\endgroup$
  • $\begingroup$ Merge[Total] will be shorter. I'm not sure if KeyValueMap fits since it destroys association. $\endgroup$ – Kuba Oct 31 '15 at 18:32
  • $\begingroup$ @Kuba Does it technically destroy the association? Or just map over the keys? $\endgroup$ – kale Oct 31 '15 at 18:35
  • $\begingroup$ I have Version 10.0 which doesn't know KeyValueMap $\endgroup$ – eldo Oct 31 '15 at 18:35
  • $\begingroup$ @eldo Oops, introduced in 10.1... $\endgroup$ – kale Oct 31 '15 at 18:37
  • $\begingroup$ @Kuba, ah, you're right. KeyValueMap returns a list for some insane reason. $\endgroup$ – kale Oct 31 '15 at 18:40
2
$\begingroup$

Not so compact

GroupBy[AssociationMap[Reverse][as], #[[2]] &, Total @* Keys]
$\endgroup$
  • 1
    $\begingroup$ It would be nice to have some kind of third argument for KeyMap to specify type of Merging. $\endgroup$ – Kuba Oct 31 '15 at 21:06

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.