# Join lists of lists with unique id

Sorry for the vague title, but I can't describe my problem properly and shortly.

I am maintaining a list of players and their games with the following form:

gamesPerPlayer =
{{playerId -> playerId1, games-> {game11, game12, game13}},
{playerId -> playerId2, games-> {game21, game22, game23, game24}}}


Each game is a complex structure of nested lists but it has a unique field, so we can simply and think that each game is just {idGame, infoGame}. Thus my list is like this

gamesPerPlayer =
{{playerId -> playerId1,
games -> {{idGame11, infoGame11}, {idGame12, infoGame12}, {idGame13, infoGame13}}},
{playerId -> playerId2,
games -> {{idGame21, infoGame21}, {idGame22, infoGame22}}}


How can I write a (fast) function to join two of this lists eliminating duplicates? The order of the playerId and the games in the new list is not important.

Just to clarify, an example:

list1 = {{playerId -> 1, game s-> {{11, "info"}, {12, "info"}}},
{playerId -> 2, games->{{21, "info"}}}};
list2 = {{playerId -> 1, games -> {{11, "info"}, {13, "info"}}},
{playerId -> 3, games -> {{31, "info"}}}};
newList = myJoinFunction[list1, list2];


Expected result:

{{playerId -> 1, games -> {{11, "info"}, {12, "info"}, {13, "info"}}},
{playerId -> 2, games -> {{21, "info"}}, {playerId -> 3, games -> {{31, "info"}}}

• Related: 16450 Commented Mar 16, 2014 at 14:09

This looks a lot like the solution Yves came up with but I arrived at it independently:

combine[id_, tag_, rls__List] :=
{id -> #[[1, 1]], tag -> Union @@ #[[All, 2]]} & /@
GatherBy[{id, tag} /. Join[rls], First]

combine[playerId, games, list1, list2]

{{playerId -> 1, games -> {{11, "info"}, {12, "info"}, {13, "info"}}},
{playerId -> 2, games -> {{21, "info"}}},
{playerId -> 3, games -> {{31, "info"}}}}


Or, if you prefer, using Sow and Reap:

combine2[id_, tag_, rls__List] :=
Last @ Reap[Sow @@@ ({tag, id} /. Join[rls]), _, {id -> #, tag -> Union @@ #2} &]

combine2[playerId, games, list1, list2]

{{playerId -> 1, games -> {{11, "info"}, {12, "info"}, {13, "info"}}},
{playerId -> 2, games -> {{21, "info"}}},
{playerId -> 3, games -> {{31, "info"}}}}

• ... you took the time to do it properly, though. I confess to being a hardcoding bum. But it is Sunday and the sun is a-shining :D Commented Mar 16, 2014 at 14:51
• @Yves Then get off the computer and go play! :-) Commented Mar 16, 2014 at 14:51
• Beep beep zoom! Commented Mar 16, 2014 at 14:53

Abstaining from using ReplaceAll:

{DeleteDuplicates[#[[1]]][[1]],
games ->
DeleteDuplicates@Flatten[#[[2, All, 2]], 1]} & /@ (Transpose /@
GatherBy[Join[list1, list2], First])


Result:

(*{{playerId -> 1, games -> {{11, "info"}, {12, "info"}, {13, "info"}}},
{playerId -> 2, games -> {{21, "info"}}},
{playerId -> 3, games -> {{31, "info"}}}}*)