# Joining lists with same elements

Let's assume that we have the following three lists

data1 = {{1, 2}, {2, 0.1}, {3, -3.2}, {4, 4.1}, {5, 0.2}};
data2 = {{1, -3}, {2, -2.1}, {3, 1.2}, {4, -3.1}, {5, -3.1}};
data3 = {{1, 0}, {2, 3.3}, {3, 0.003}, {4, 5.2}, {5, 3.1}};


As we can see, in all three lists the first elements of each sublist are the same. Now I want to create a new list data containing the first elements of each sublist and the sums of the second elements, i.e.,

data = {{1, 2 - 3 + 0}, {2, 0.1 - 2.1 + 3.3}, {3, -3.2 + 1.2 + 0.003}, {4, 4.1 - 3.1 + 5.2}, {5, 0.2 - 3.1 + 3.1}}


Any suggestions?

I suggest you use associations, not lists of pairs.

{asc1, asc2, asc3} = AssociationThread @@ Transpose[#] & /@ {data1, data2, data3};

asc1 + asc2 + asc3
(* <|1 -> -1, 2 -> 1.3, 3 -> -1.997, 4 -> 6.2, 5 -> 0.2|> *)


Look up KeyUnion and KeyIntersection for dealing with the cases when the set of keys are not exactly the same.

You may also use TimeSeries, though I am personally not very experienced with this construct, so I will only show the simplest example:

{ts1, ts2, ts3} = TimeSeries /@ {data1, data2, data3};


Now we can do

tsSum = ts1 + ts2 + ts3


Convert back to a list:

Normal[tsSum]
(* {{1, -1}, {2, 1.3}, {3, -1.997}, {4, 6.2}, {5, 0.2}} *)


Most operations that one might want to do on time series data, such as ListPlot or LinearModelFit, will work without needing to convert the TimeSeries back to a list.

• No, this is not what I want. I want a new list as it is described in my post. – Vaggelis_Z Aug 25 '19 at 10:59
• You can convert the resulting Association to a list by doing List @@@ Normal@myassoc – Carl Lange Aug 25 '19 at 11:14
• @Vaggelis_Z Why do you want a new list? My point is that it is usually much more convenient to use associations for this type of data. What's the next thing you want to do with that list? Can it not be done with associations? Often, not only can it be done, it's also easier to do. And as Carl said, converting back to a list is trivial. (See also KeyValueMap.) – Szabolcs Aug 25 '19 at 11:52
Values @ GroupBy[Join[data1, data2, data3], First, {#[[1, 1]], Total[#[[All, 2]]]} &]


{{1, -1}, {2, 1.3}, {3, -1.997}, {4, 6.2}, {5, 0.2}}

Also (thanks WReach):

KeyValueMap[List] @ GroupBy[Join[data1, data2, data3], First -> Last,Total]


{{1, -1}, {2, 1.3}, {3, -1.997}, {4, 6.2}, {5, 0.2}}

More generally, if the input lists are ragged lists:

KeyValueMap[List] @ GroupBy[Join[data1, data2, data3], First -> Rest, First@*Total]

• +1. In the second case, we could write GroupBy[..., First -> Last, Total]. – WReach Aug 26 '19 at 4:36
• Thank you @WReach. Updated with the suggested form. – kglr Aug 26 '19 at 4:47
{#[[1, 1]], #[[All, 2]] // Total} & /@ GatherBy[Join[data1, data2, data3], First]


{{1, -1}, {2, 1.3}, {3, -1.997}, {4, 6.2}, {5, 0.2}}

You can use Query:

{data1, data2, data3} // Transpose // Query[ All, Transpose /* {1 /* First, 2 /* Total} ]


{{1, -1}, {2, 1.3}, {3, -1.997}, {4, 6.2}, {5, 0.2}}

Alternatively we can initiate the Query using GatherBy as suggested by C. E.'s answer:

{data1, data2, data3} // RightComposition[
Apply@Join,
GatherBy[ #, First ]&,
Query[ All, Transpose /* {1 /* First, 2 /* Total} ]
]

• +1. In the first example, we can combine the transpositions: Transpose[{data1, data2, data3}, {3, 1, 2}] // Query[All, {1 /* First, 2 /* Total}] – WReach Aug 26 '19 at 4:20

You can use MapThread to do this,

combiner[patt : ({x_, _} ..)] := {x, Total[{patt}[[All, 2]]]}

(* {{1, -1}, {2, 1.3}, {3, -1.997}, {4, 6.2}, {5, 0.2}} *)

data1 = {{1, 2}, {2, 0.1}, {3, -3.2}, {4, 4.1}, {5, 0.2}};
data2 = {{1, -3}, {2, -2.1}, {3, 1.2}, {4, -3.1}, {5, -3.1}};
data3 = {{1, 0}, {2, 3.3}, {3, 0.003}, {4, 5.2}, {5, 3.1}};

data = {#[[1, 1]],
Inactive[Plus] @@ #[[All, 2]]} & /@
(Join[data1, data2, data3] //
GatherBy[#, First] &)


data // Activate

(* {{1, -1}, {2, 1.3}, {3, -1.997}, {4, 6.2}, {5, 0.2}} *)


Another short solution:

data = Rule @@@ Join[data1, data2, data3] // Merge[Total] // KeyValueMap[List]


I would also suggest using associations, but I would use Merge to total them:

{ass1, ass2, ass3} = Apply[Rule, {data1, data2, data3}, {2}];

Merge[{ass1, ass2, ass3}, Total]


<|1 -> -1, 2 -> 1.3, 3 -> -1.997, 4 -> 6.2, 5 -> 0.2|>