# How to sum over duplicates?

I have a list of the form:

{{1, 0, 1}, {2, 1, 2}, {1, 0, 3}, {2, 4, 2}, {2, 1, -1}, {1, 0 ,0}}


that I would like to sort such that I calculate the sum over the third column whenever the first two columns are equal. I.e. in this case the output would be

{{1, 0, 1 + 3 + 0}, {2, 1, 2 + (-1)}, {2, 4, 2}}


or

 {{1, 0, 4},{2, 1, 1},{2, 4, 2}}


Is there an elegant way to do this?

• Duplicate of: mathematica.stackexchange.com/q/4332/5 Also related: mathematica.stackexchange.com/q/16115/5 – rm -rf Dec 18 '12 at 0:39
• @rm-rf Looking at your first link the principle is the same. However gathering based on both first and second columns, as opposed to just the first, is probably not obvious to a new user. Keeping the first 2 columns together also means that you have to wrap Flatten around the mapped function. – Mike Honeychurch Dec 18 '12 at 0:43

Flatten[{#[[1, {1, 2}]], Total[#[[All, 3]]]}] & /@ GatherBy[yourList, #[[{1, 2}]] &]

(*  {{1, 0, 4}, {2, 1, 1}, {2, 4, 2}} *)


How this works:

GatherBy[yourList, #[[{1, 2}]] &]


this gathers elements of your list based on matching the first and second elements in each sub-list (#[[{1, 2}]] &)

Once common elements are gathered (collected) you can total/sum all the third elements by mapping them onto Total

• Perfect! I was unaware of the GatherBy function and, yes, using it with more than one column was not obvious to this new user. – Paul Dec 18 '12 at 0:48
 lists = {{1, 0, 1}, {2, 1, 2}, {1, 0, 3}, {2, 4, 2}, {2, 1, -1}, {1, 0, 0}}


Reap/Sow:

 Reap[Sow[#[[3]], {#[[{1, 2}]]}] & /@ lists, _,  Append[#1, Total@#2] &][[2]]


ReplaceRepeated:

 lists //. {a___, {x_, y_, z_}, b___, {x_, y_, w_}, c___} :> {a, {x, y, z + w}, b, c}


Cases + DeleteDuplicates:

 DeleteDuplicates@Cases[lists, {w : PatternSequence[_, _], _} :>
{w, Total@(Last /@ Cases[lists, {w, _}])}]


all give

{{1, 0, 4}, {2, 1, 1}, {2, 4, 2}}

Update: In versions 10+, you can also use Merge:

KeyValueMap[Append]@Merge[Tr][Most @ # -> Last @ #& /@ lists]


{{1, 0, 4}, {2, 1, 1}, {2, 4, 2}}

• +1 for the ReplaceRepeated. – image_doctor Dec 18 '12 at 10:25
Total@#/PadLeft[{1}, 3, Length@#] & /@ GatherBy[list, #[[{1, 2}]] &]


This approach is basically the same as Mike's. However, instead of summing only the last element it sums all the elements. To correct for the extra summing PadLeft[{1}, 3, Length@#] is used to divide by the number of times it was added where the {1} is included to keep the last element the same. The approach can be generalized to lists of length $n$ by replacing PadLeft[{1}, 3, Length@#] with PadLeft[{1}, Length@#[[1]], Length@#]

• You might give a bit of explanation as to what your code is doing and why it works. – Brett Champion Dec 18 '12 at 4:57

GroupBy, introduced in Mathemtaica 10, is applicable here and cleaner than GatherBy:

in = {{1, 0, 1}, {2, 1, 2}, {1, 0, 3}, {2, 4, 2}, {2, 1, -1}, {1, 0, 0}};

Append @@@ Normal @ GroupBy[in, Most -> Last, Tr]

{{1, 0, 4}, {2, 1, 1}, {2, 4, 2}}


Since GatherBy and Sow/Reap are already shown I'll drop back to "first principles" as it were and use more basic language.

dat = {{1, 0, 1}, {2, 1, 2}, {1, 0, 3}, {2, 4, 2}, {2, 1, -1}, {1, 0, 0}};

f[dat_] :=
Module[{key},
key[__] = 0;
key[#, #2] += #3 & @@@ dat;
Most @ DownValues @ key /. (_@_@x__ :> y_) :> {x, y}
]

f @ dat

{{1, 0, 4}, {2, 1, 1}, {2, 4, 2}}