# How to combine two lists of pairs based on the first elements of those pairs

I have two lists like the ones below:

listA = {{1, "a"}, {2, "b"}, {3, "c"}, {4, "d"}, {5, "e"}};
listB = {{1, "A"}, {2, "B"}, {3, "C"}, {4, "D"}, {5, "E"}};

I need to combine them based on the first elements as the key to get something like this:

{{1, "a", "A"}, {2, "b", "B"}, {3, "c", "C"}, {4, "d", "D"}, {5, "e", "E"}}

Or, since I know that both these lists have the same first elements in the same order, maybe it is easier to strip the Last values in the second list and add them to the first list.... whichever way is easier...

Thank you!

If you know that the lists have the same length and the same first elements of each element in the first order, as you said, then a "fragile" approach could be

combinedList = MapThread[Append[#1, Last[#2]] &, {listA, listB}]

If these really are key-value pairs, consider turning them into Associations and using Merge:

assocA = Association[Rule @@@ listA]
assocB = Association[Rule @@@ listB]

combinedAssoc = Merge[{assocA, assocB}, Identity]

Turn an association back into a list of lists of key-value pairs (instead of Rules, which is what Normal gives) if you want:

KVlist[a_] := List @@@ Normal[a]
• Perfect, thank you! the "fragile" approach works just fine for me! Commented Nov 30, 2022 at 6:24
\$Version

(* "13.1.0 for Mac OS X x86 (64-bit) (June 16, 2022)" *)

Clear["Global`*"]

listA = {{1, "a"}, {2, "b"}, {3, "c"}, {4, "d"}, {5, "e"}};
listB = {{1, "A"}, {2, "B"}, {3, "C"}, {4, "D"}, {5, "E"}};

For the given structure (shared order)

{#[[1, 1]], #[[1, 2]], #[[2, 2]]} & /@ Transpose[{listA, listB}]

(* {{1, "a", "A"}, {2, "b", "B"}, {3, "c", "C"}, {4, "d", "D"},
{5, "e", "E"}} *)

If they are not necessarily aligned in the same fashion

Flatten[{listA, listB}, 1] //.
{s___, {n_, str1_String}, m___, {n_, str2_String}, e___} :>
{s, {n, str1, str2}, m, e}

(* {{1, "a", "A"}, {2, "b", "B"}, {3, "c", "C"}, {4, "d", "D"},
{5, "e", "E"}} *)

% === %%

(* True *)
listA = {{1, "a"}, {5, "e"}, {2, "b"}, {3, "c"}, {4, "d"}, {6, "e"}};
listB = {{2, "B"}, {4, "D"}, {3, "C"}, {5, "E"}, {7, "F"}, {1, "A"}};

I have added an extra unmatched pair in each list and shuffled the order. Define this function.

mergePairs[k1_List, k2_List] := Module[{assocA, assocB},
assocA = Association[Rule @@@ k1];
assocB = Association[Rule @@@ k2];
(Merge[{assocA, assocB}, Apply@Sequence] // Normal) /. Rule -> List
]

mergePairs[listA, listB]

Or if you want to do it using list manipulation only, you can join the two lists and GatherBy the first items and perform a Union. This way many lists can be combined without having to define an association for each.

Union @@@ GatherBy[Catenate[{listA, listB}], First]

As pointed out, duplicates are deleted by Union.

To retain non-unique elements in the second position, take the first element of any gathered list and join with all the last elements:

Sequence @@@ {#[[1, 1]], #[[All, 2]]} & /@
GatherBy[Catenate[{listA, listB}], First]

Result

{{1, "a", "A"}, {5, "e", "E"}, {2, "b", "B"}, {3, "c", "C"}, {4, "d", "D"}, {6, "e"}, {7, "F"}}

• Thanks, Syed. the Union drops non-unique values, that does not work for me. Thank you, though Commented Nov 30, 2022 at 6:25
• @IgorBinder Thanks for the feedback. I have updated the answer.
– Syed
Commented Nov 30, 2022 at 6:33
Cases[GatherBy[Join[listA,listB],First],{{x1_,y1_},{x2_,y2_}}:> {x1,y1,y2}]

{{1, a, A}, {2, b, B}, {3, c, C}, {4, d, D}, {5, e, E}}

Check

Cases[GatherBy[Join[listA,listB[[RandomSample@Range@Length@listB]]],First],{{x1_,y1_},{x2_,y2_}}:> {x1,y1,y2}]

{{1, a, A}, {2, b, B}, {3, c, C}, {4, d, D}, {5, e, E}}

Just another way to do this:

MapApply[Composition[DeleteDuplicates, Join], Transpose[{listA, listB}]]
(*{{1, "a", "A"}, {2, "b", "B"}, {3, "c", "C"}, {4, "d", "D"}, {5, "e", "E"}}*)
a = {{1, "a"}, {2, "b"}, {3, "c"}, {4, "d"}, {5, "e"}};

b = {{1, "A"}, {2, "B"}, {3, "C"}, {4, "D"}, {5, "E"}};

Using GroupBy

KeyValueMap[Flatten @* List] @ GroupBy[Join[a, b], First -> Rest]

{{1, "a", "A"}, {2, "b", "B"}, {3, "c", "C"}, {4, "d", "D"}, {5, "e", "E"}}