7

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?

march
  • 23,399
  • 2
  • 44
  • 100
Sayan Biswas
  • 157
  • 3

8 Answers8

6
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}}  *)
Bob Hanlon
  • 157,611
  • 7
  • 77
  • 198
3

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.

Edmund
  • 42,267
  • 3
  • 51
  • 143
  • If I were to use GroupBy, I'd do: KeyValueMap[Prepend[#2, #1] &]@ GroupBy[Join[t1, t2, t3], First -> Rest, Total]. – Sjoerd Smit Jan 08 '24 at 14:36
3

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}}] )
march
  • 23,399
  • 2
  • 44
  • 100
  • Equivalently {First@#1, Tr@#2} & @@@ Flatten[{t1, t2, t3}, {{2}, {3}}] – Simon Woods Nov 08 '16 at 17:30
  • @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. – march Nov 08 '16 at 17:47
3

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}}

eldo
  • 67,911
  • 5
  • 60
  • 168
3

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}} *)

Syed
  • 52,495
  • 4
  • 30
  • 85
E. Chan-López
  • 23,117
  • 3
  • 21
  • 44
3

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}}

Syed
  • 52,495
  • 4
  • 30
  • 85
3

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}}
138 Aspen
  • 1,269
  • 3
  • 16
1

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}} *)

user1066
  • 17,923
  • 3
  • 31
  • 49