Sunday 21 July 2013

Cartesian Product code sample, LINQ, C#

Starting point
StackOverflow: Cartesian Product + N x M Dynamic Array

Credit: Eric Lippert

Sample code (C#, console app)

namespace CartesianStudy
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    public static class Program
    {
        public static void Main()
        {
            var persons = new[]
                {
                    "Peter", 
                    "Mary", 
                    "Ivan", 
                    "Oscar", 
                    "Lucy"
                };

            var flyingDays = new List<string>
                {
                    "Tue", 
                    "Wed", 
                    "Fri", 
                };

            var flights = new List<Flight>
                {
                    new Flight("Air Canada", "AC1152"), 
                    new Flight("CanJet", "C6785"), 
                    new Flight("WestJet", "WS4040"),
                    new Flight("SunWing", "WG423"),
                    new Flight("Air Canada", "AC093"),
                    new Flight("American Airlines", "AA8118"),
                };

            var allCombinations = new IEnumerable<object>[]
                    {
                        persons, flyingDays, flights
                    }.CartesianProduct().ToList();

            foreach (var combination in allCombinations
                .Select(c => c.ToList()))
            {
                Console.WriteLine(
                    "{0} on {1} by {2}", 
                    combination[0], 
                    combination[1], 
                    combination[2]);
            }

            Console.WriteLine(
                "\nCount: {0}\nAny key...", 
                allCombinations.Count);
            
            Console.ReadKey();
        }

        private static IEnumerable<IEnumerable<T>> 
            CartesianProduct<T>(
            this IEnumerable<IEnumerable<T>> sequences)
        {
            IEnumerable<IEnumerable<T>> emptyProduct = new[]
                {
                    Enumerable.Empty<T>()
                };

            return sequences.Aggregate(
                emptyProduct,
                (accumulator, sequence) =>
                from accseq in accumulator
                from item in sequence
                select accseq.Concat(new[] { item }));
        }
    }

    public class Flight
    {
        public string Company { get; set; }

        public string Number { get; set; }

        public Flight(string company, string number)
        {
            this.Company = company;
            this.Number = number;
        }

        public override string ToString()
        {
            return string.Format(
                "{0} - {1}", 
                this.Company, 
                this.Number);
        }
    }
}