Tartar
Tartar

Reputation: 5452

F#: Grouping a complex list

I am trying to group the list by each element of player list

let playersScore= [ 
  (["Player 1";"Player 2";], "First Game");
  (["Player 2";"Player 3";"Player 4";], "Second Game");
  (["Player 3"], "Third Game");
  (["Player 1";"Player 2";"Player 3";"Player 4";], "Last Game")] : scorePlayerItem list

What I want to get is to find which player has joined to which games as

(string * string list) list

For example according to that list

  1. Player1 -> First Game, Last Game
  2. Player2 -> First Game, Second Game
  3. Player3 -> Second, Third Game, Last Game
  4. Player4 -> Second Game, Last Game

I tried to use List.groupBy but could not achive this. I just could not manage to group items by each element of player list.

Any help would be appreciated.

Upvotes: 2

Views: 139

Answers (1)

Aaron M. Eshbach
Aaron M. Eshbach

Reputation: 6510

Here's a fairly simple solution:

let groups =
    playersScore
    |> List.collect (fun (players, game) -> players |> List.map (fun player -> player, game))
    |> List.groupBy (fun (player, _) -> player)
    |> Map.ofList
    |> Map.map (fun _ games -> games |> List.map snd)

Break out the list of lists into a flat structure, group them by player, then convert to a map with the player as the key, and finally map the values to get just the name of the game. This produces the following map:

map
  [("Player 1", ["First Game"; "Last Game"]);
   ("Player 2", ["First Game"; "Second Game"; "Last Game"]);
   ("Player 3", ["Second Game"; "Third Game"; "Last Game"]);
   ("Player 4", ["Second Game"; "Last Game"])]

EDIT

To keep things as a list, you can just use List.map instead of Map.ofList and Map.map:

let groups =
    playersScore
    |> List.collect (fun (players, game) -> players |> List.map (fun player -> player, game))
    |> List.groupBy (fun (player, _) -> player)
    |> List.map (fun (player, games) -> player, games |> List.map snd)

This returns the equivalent result as a list:

[("Player 1", ["First Game"; "Last Game"]);
 ("Player 2", ["First Game"; "Second Game"; "Last Game"]);
 ("Player 3", ["Second Game"; "Third Game"; "Last Game"]);
 ("Player 4", ["Second Game"; "Last Game"])]

Upvotes: 3

Related Questions