7
$\begingroup$

I have three tables of data say

t1 = {{1, 2}, {2, 3}, {3, 4}};
t2 = {{1, 3}, {2, 3}, {3, 5}};
t3 = {{1, 3}, {2, 3}};

First I want to add t1 and t2 such that first data in the brace remains same but the second data of the two tables are added up.

For an example:

tsum1 = {{1,5},{2,6},{3,9}};

How can I do it in Mathematica?

If I want to add t1, t2 and t3 (t3 has less number of data set than t1 and t2) such that first data points remain same but the second ones are added up.

For an example

tsum2 = {{1,8},{2,9},{3,9}};

How can I do it with Mathematica?

$\endgroup$

9 Answers 9

8
$\begingroup$
t1 = {{1, 2}, {2, 3}, {3, 4}};
t2 = {{1, 3}, {2, 3}, {3, 5}};
t3 = {{1, 3}, {2, 3}};

sum[x : (_?ArrayQ ..)] := Module[
  {maxLen, xp, yp},
  maxLen = Max[Length /@ {x}];
  xp = Select[{x}, Length[#] == maxLen &][[1, All, 1]];
  yp = Plus @@ (PadRight[#[[All, 2]], maxLen, 0] & /@ {x});
  Transpose[{xp, yp}]]

tsum1 = sum[t1, t2]

(*  {{1, 5}, {2, 6}, {3, 9}}  *)

tsum2 = sum[t1, t2, t3]

(*  {{1, 8}, {2, 9}, {3, 9}}  *)

EDIT: A more robust approach using ReplaceRepeated

sum2[x : (_?ArrayQ ..)] := (Join @@ {x}) //.
  {s___, {a_, b_}, m___, {a_, c_}, e___} :>
   {s, {a, b + c}, m, e}

tsum1 = sum2[t1, t2]

(*  {{1, 5}, {2, 6}, {3, 9}}  *)

tsum2 = sum2[t1, t2, t3]

(*  {{1, 8}, {2, 9}, {3, 9}}  *)

t4 = {{3, 5}, {1, 3}};

tsum3 = sum2[t1, t2, t4]

(*  {{1, 8}, {2, 6}, {3, 14}}  *)
$\endgroup$
1
  • $\begingroup$ Thanks for the solution $\endgroup$ Commented Nov 8, 2016 at 7:07
4
$\begingroup$

You may use GatherBy and Total. Or GroupBy and KeyValueMap with Total.

{#[[1, 1]], Total@#[[All, 2]]} & /@ GatherBy[Join @@ {t1, t2, t3}, First]

or

KeyValueMap[{#1, Total@#2[[All, 2]]} &]@GroupBy[Join @@ {t1, t2, t3}, First]

both give

{{1, 8}, {2, 9}, {3, 9}}

Hope this helps.

$\endgroup$
1
  • $\begingroup$ If I were to use GroupBy, I'd do: KeyValueMap[Prepend[#2, #1] &]@ GroupBy[Join[t1, t2, t3], First -> Rest, Total]. $\endgroup$ Commented Jan 8 at 14:36
4
$\begingroup$

A short one-liner, taking advantage of the second argument of Flatten to perform a ragged transpose:

{First@#1, Tr@#2} & @@@ Flatten[{t1, t2, t3}, {{2}, {3}}]

(Thank to Simon Woods for changing

Thread /@ Flatten[{t1, t2, t3}, {{2}}]

to

Flatten[{t1, t2, t3}, {{2}, {3}}] )
$\endgroup$
2
  • $\begingroup$ Equivalently {First@#1, Tr@#2} & @@@ Flatten[{t1, t2, t3}, {{2}, {3}}] $\endgroup$ Commented Nov 8, 2016 at 17:30
  • $\begingroup$ @SimonWoods. Thank you! I was looking for that, but I still haven't sat down and really figured out that second argument to Flatten (despite the nice answers here), and so I couldn't figure it out. $\endgroup$
    – march
    Commented Nov 8, 2016 at 17:47
3
$\begingroup$

MapThread with 2 arrays of equal lengths

t1 = {{1, 2}, {2, 3}, {3, 4}};
t2 = {{1, 3}, {2, 3}, {3, 5}};

MapThread[{#1[[1]], #1[[2]] + #2[[2]]} &, {t1, t2}]

{{1, 5}, {2, 6}, {3, 9}}

MapThread with 3 arrays of unequal lengths

t1 = {{1, 2}, {2, 3}, {3, 4}};
t2 = {{1, 3}, {2, 3}, {3, 5}};
t3 = {{1, 3}, {2, 3}};

PadRight automatically pads with {0,0}

MapThread[{#1[[1]], #1[[2]] + #2[[2]] + #3[[2]]} &, PadRight[{t1, t2, t3}]]

{{1, 8}, {2, 9}, {3, 9}}

More flexible are Association-related functions

KeyValueMap[List] @ Merge[Total] @ MapApply[Rule] @ Join[t1, t2, t3]

{{1, 8}, {2, 9}, {3, 9}}

Edmund's solution can be simplified to

KeyValueMap[List] @ GroupBy[Join[t1, t2, t3], First -> Last, Total]

{{1, 8}, {2, 9}, {3, 9}}

$\endgroup$
3
$\begingroup$

Using ArrayReduce:

t1 = {{1, 2}, {2, 3}, {3, 4}};
t2 = {{1, 3}, {2, 3}, {3, 5}};
t3 = {{1, 3}, {2, 3}};

s1 = ArrayReduce[
  Total@*Union, #[[All, All, 1]] &@PadRight[{t1, t2, t3}], 1];

s2 = ArrayReduce[Total, #[[All, All, 2]] &@PadRight[{t1, t2, t3}], 1];

Transpose[{s1, s2}]

{{1, 8}, {2, 9}, {3, 9}}

$\endgroup$
3
$\begingroup$

Using With, Reap and Sow:

t1 = {{1, 2}, {2, 3}, {3, 4}};
t2 = {{1, 3}, {2, 3}, {3, 5}};
t3 = {{1, 3}, {2, 3}};

With[{lst = {t1, t2}, l = Length@{t1, t2}}, 
Reap[Do[Sow[#[[2]], #[[1]]] & /@ Join @@ #, {i, l}], _, {#1, Total@#2/l} &][[2]] &@lst]

(*{{1, 5}, {2, 6}, {3, 9}}*)

With[{lst = {t1, t2, t3}, l = Length@{t1, t2, t3}}, 
Reap[Do[Sow[#[[2]], #[[1]]] & /@ Join @@ #, {i, l}], _, {#1, Total@#2/l} &][[2]] &@lst]

(*{{1, 8}, {2, 9}, {3, 9}}*)

MapIndexed[{First@#2, Total@#1} &, 
 Last@Reap@Scan[Sow[Last@#, First@#] &, Flatten[{t1, t2, t3}, 1]]]

(* {{1, 8}, {2, 9}, {3, 9}} *)
$\endgroup$
3
$\begingroup$

Recommend

Convert List to Association, then Merge the Associations, finally convert Association to List.

Clear["Global`*"];
t1 = {{1, 2}, {2, 3}, {3, 4}};
t2 = {{1, 3}, {2, 3}, {3, 5}};
t3 = {{1, 3}, {2, 3}};

(*Create associations*)
myListToAssociation[lst_] := 
  assoc1 = Association[(#1 -> #2) & @@@ lst];

(*Merge associations and total the values*)
assocSum = Merge[myListToAssociation /@ {t1, t2, t3}, Total]

(*Convert the association back to a list*)
tsum2 = {#, assocSum[#]} & /@ Keys[assocSum]
<|1 -> 8, 2 -> 9, 3 -> 9|>
{{1, 8}, {2, 9}, {3, 9}}

DO NOT recommend

zip (to some degree) the lists, then processing the data.

t1 = {{a2, 2}, {2, 3}, {3, 4}};
t2 = {{a1, 3}, {2, 3}, {3, 5}};

tsum1 = MapThread[{First[#1], Last[#1] + Last[#2]} &, {t2, t1}]
{{a1, 5}, {2, 6}, {3, 9}}
$\endgroup$
2
$\begingroup$

A variation on using Flatten to transpose a ragged array:

MapThread[{First@#1,Total[#2]}&,(Flatten[{t1,t2,t3},{{3},{2}}])]

(* {{1,8},{2,9},{3,9}} *)
$\endgroup$
1
$\begingroup$
t1 = {{1, 2}, {2, 3}, {3, 4}};
t2 = {{1, 3}, {2, 3}, {3, 5}};
t3 = {{1, 3}, {2, 3}};

Using MultisetSum by Robert B. Nachbar (Wolfram Solutions)

MultisetSum = ResourceFunction["MultisetSum"];

MultisetSum @@ Association @@@ Apply[Rule, {t1, t2, t3}, {2}]

<|1 -> 8, 2 -> 9, 3 -> 9|>

Association to List

KeyValueMap[List][%]

{{1, 8}, {2, 9}, {3, 9}}

$\endgroup$

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.