5
$\begingroup$

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"}}}
$\endgroup$
1
  • 1
    $\begingroup$ Related: 16450 $\endgroup$
    – Michael E2
    Mar 16, 2014 at 14:09

2 Answers 2

6
$\begingroup$

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"}}}}
$\endgroup$
3
  • 1
    $\begingroup$ ... 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 $\endgroup$
    – Yves Klett
    Mar 16, 2014 at 14:51
  • $\begingroup$ @Yves Then get off the computer and go play! :-) $\endgroup$
    – Mr.Wizard
    Mar 16, 2014 at 14:51
  • 1
    $\begingroup$ Beep beep zoom! $\endgroup$
    – Yves Klett
    Mar 16, 2014 at 14:53
6
$\begingroup$

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"}}}}*)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.