Introduction
Several times, I got a request to build an application to support a sportsclub (e.g. table tennis) to keep track of / administer the competition progress. To do this in a correct matter, games must be generated automatically when a player has been added to a competition. Of course, this can be automated and this is explained in this article by using Linq.
Background
The Cartesian product is the mathematical way to solve this but, it generates also product with the same player which is not possible.
e.g. Player A versus Player A
and it also generates duplicates Player A versus Player B and Player B versus Player A which is the same game.
So the generated list must be filtered. The filtering is done by using a unique id per player and only add the last/second reference of a duplicate.
Using the Code
Two classes are used to store player data and the resulting game data:
public class Player
{
Public String Name {get; private set;}
Public int ID {get; private set;}
public Player(String name, int id)
{
Name = name;
ID = id;
}
}
public class Game
{
public String PlayerA { get; private set; }
public String PlayerB { get; private set; }
public Game(String A, String B)
{
PlayerA = A;
PlayerB = B;
}
}
To use these classes, the following code is used in the Form1.cs:
private List<Player> Names = new List<Player>();
private List<Game> Games = new List<Game>();
public Form1()
{
InitializeComponent();
Names.Add(new Player("Andre",1));
Names.Add(new Player("Luke", 2));
Names.Add(new Player("Des", 3));
Names.Add(new Player("Patrick", 4));
dataGridView1.DataSource = Names;
dataGridView2.DataSource = Games;
}
private void Generate()
{
Games.Clear();
var query = Names.SelectMany(x => Names, (x, y) => new { x, y });
foreach (var q in query)
{
if ((q.x.Name != q.y.Name)&& (q.y.ID > q.x.ID))
Games.Add(new Game(q.x.Name, q.y.Name));
}
Games.Sort((x, y) => string.Compare(x.PlayerA, y.PlayerA));
}
The form is initialized with 4 players (and shown in dataGridView1
). By adding the names, dataGridView1
fires the event "Row Added" which on its turn calls Generate()
.
The Generate
function clears the list, generates the Cartesian product list with 15 results based on 4 players. After obtaining the Cartesian product list, each result is filtered and added as a new game to the game list. Filtering is done when the game has no duplicate players and it's the second result. (Case A vs B and B vs A)
And since the Game list is databound to dataGridView2
, the view is automatically updated and shows the games to play.
Points of Interest
From an educational point of view, the Cartesian product is the solution but to do it with Linq was something to find out.
History
- 2nd September, 2014: Initial version