# 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. Commented Aug 25, 2019 at 10:59
• You can convert the resulting Association to a list by doing List @@@ Normal@myassoc Commented Aug 25, 2019 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.) Commented Aug 25, 2019 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]. Commented Aug 26, 2019 at 4:36
• Thank you @WReach. Updated with the suggested form.
– kglr
Commented Aug 26, 2019 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}] Commented Aug 26, 2019 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|>