3
$\begingroup$

I have an Association in which values are lists of lists containing an Integer and a DateObject. I would like to build a function that adds all Integers that have the same dates.

assoc = <| "first" -> {{1,DateObject[{2019,1}]},{2,DateObject[{2019,3}]},{3,DateObject[{2019,7}]},{4,DateObject[{2019,1}]}}, "Second" ->{{1,DateObject[{2019,1}]},{2,DateObject[{2019,8}]},{3,DateObject[{2019,7}]},{4,DateObject[{2019,8}]}}|>

I am looking for a function F for which: response = F/@assoc

Where respnse will result in: assoc = <| "first" -> {{5,DateObject[{2019,1}]},{2,DateObject[{2019,3}]},{3,DateObject[{2019,7}]}}, "Second" ->{{1,DateObject[{2019,1}]},{6,DateObject[{2019,8}]},{3,DateObject[{2019,7}]}}|>

Is there any clever pattern matching way to do this for the general case?

Thanks!

$\endgroup$
4
$\begingroup$

Update: "Adding values (...) through pattern matching":

You can use ReplaceRepeatedas follows:

rule = {a___, {b_, c_DateObject}, d___, {e_, c_}, f___} :> {a, {b + e, c}, d, f};

ReplaceRepeated[rule] /@ assoc

enter image description here

Original answer:

f1 = Map[Values @ GroupBy[#, Last, {Total[First /@ #], #[[1, 2]]} &] &];
f1 @ assoc

enter image description here

Also

f2 = Map[{Total[#[[All, 1]]], #[[1, 2]]} & /@ GatherBy[#, Last] &];

f2 @ assoc

same result

f3 = Map[{Total[#[[All, 1]]], #[[1, 2]]} & /@ SplitBy[#, Last] & @* SortBy[Last]];

f3 @assoc

enter image description here

Alternatively,

Dataset[assoc][All, GroupBy[Last], Total /* First]

enter image description here

$\endgroup$
3
  • $\begingroup$ Thank you @kglr, this does solve my issues. I was hoping I could find a way to do this with rules or pattern matching, but perhaps that is the wrong approach! $\endgroup$ Mar 17 '20 at 14:10
  • $\begingroup$ @MathematicaUser, my pleasure. $\endgroup$
    – kglr
    Mar 17 '20 at 20:44
  • $\begingroup$ @MathematicaUser, please see the update re suing rules and pattern matching to get the same result. $\endgroup$
    – kglr
    Mar 17 '20 at 21:58
3
$\begingroup$

Here is a way that uses version 12.1's shiny new SubsetReplace:

SubsetReplace[x:{{_, d_} ..} :> {Total@x[[All, 1]], d}] /@ assoc

result screenshot

$\endgroup$
2
$\begingroup$

You may use Query.

Query[All, GroupBy[Last -> First] /* KeyValueMap[Reverse[{##}] &], Total]@assoc

enter image description here

Hope this helps.

$\endgroup$

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.