It can be expanded to multiple sets. In A similar example, if A represents A set of students in A school and B represents A set of all courses in the school, the cartesian products of A and B represent all possible course selections.
Copy codeThe Code is as follows: using System;
Using System. Collections. Generic;
Using System. Diagnostics;
Using System. Linq;
Namespace Algorithm
{
Public static class Algorithm
{
/// <Summary>
/// Cartesian Product
/// </Summary>
Public static List <T> CartesianProduct <T> (this List <T> lstSplit)
{
Int count = 1;
LstSplit. ForEach (item => count * = item. Count );
// Count = lstSplit. Aggregate (1, (result, next) => result * next. Count );
Var lstResult = new List <T> ();
For (int I = 0; I <count; ++ I)
{
Var lstTemp = new List <T> ();
Int j = 1;
LstSplit. ForEach (item =>
{
J * = item. Count;
LstTemp. Add (item [(I/(count/j) % item. Count]);
});
LstResult. Add (lstTemp );
}
Return lstResult;
}
}
Class Program
{
Public static void Main ()
{
StringDemo ();
Generate a Routing Demo () based on the Sector ();
Generate a Routing Demo2 () based on the Sector ();
}
/// <Summary>
/// Cartesian product of a simple string
/// </Summary>
Private static void StringDemo ()
{
Var lstSource = new List <string>
{
New List <string> () {"A", "B", "C "},
New List <string> () {"D", "E", "F "},
New List <string> () {"G", "H", "I "},
};
Var sw = new Stopwatch ();
Sw. Start ();
Var lstResult = lstSource. CartesianProduct ();
Console. WriteLine (sw. Elapsed );
}
Private static void generate a Routing Demo () based on the Sector ()
{
// Multiple bookingclasses are allowed by default, indicating that any one can be used.
Var lstSectorDef = new List <Sector>
{
New Sector {SeqNO = 1, BookingClass = "A/A1/A2 "},
New Sector {SeqNO = 2, BookingClass = "B/B1/B2 "},
New Sector {SeqNO = 3, BookingClass = "C/C1/C2 "},
// The number of... is not fixed
};
Var sw = new Stopwatch ();
Sw. Start ();
Var lstSectorGroup = new List <Sector> ();
LstSectorDef. ForEach (item =>
{
Var lstSector = new List <Sector> ();
Foreach (var bookingClass in item. BookingClass. Split ('/'))
{
Var sector = item. Clone ();
Sector. BookingClass = bookingClass;
LstSector. Add (sector );
}
LstSectorGroup. Add (lstSector );
});
Var lstRouting = lstSectorGroup. CartesianProduct ();
Console. WriteLine (sw. Elapsed );
}
Private static void: generate the Routing Demo2 () based on the Sector ()
{
// Multiple bookingclasses are allowed by default, indicating that any one can be used.
Var lstSectorDef = new List <Sector>
{
New Sector {SeqNO = 1, BookingClass = "A1/A2/A3 "},
New Sector {SeqNO = 2, BookingClass = "B1/B2/B3 "},
New Sector {SeqNO = 3, BookingClass = "C1/C2/C3 "},
// The number of... is not fixed
};
Var sw = new Stopwatch ();
Sw. Start ();
Var lstTemp = new List <string> ();
LstSectorDef. ForEach (item =>
{
LstTemp. Add (item. BookingClass. Split ('/'). ToList ());
});
Var lstBookingClassGroup = lstTemp. CartesianProduct ();
Var lstRouting = new List <Sector> ();
For (int I = 0; I <lstBookingClassGroup. Count; I ++)
{
Var lstSector = new List <Sector> ();
For (int j = 0; j <lstSectorDef. Count; j ++)
{
Var sector = lstSectorDef [j]. Clone ();
Sector. BookingClass = lstBookingClassGroup [I] [j];
LstSector. Add (sector );
}
LstRouting. Add (lstSector );
}
Console. WriteLine (sw. Elapsed );
}
}
[DebuggerDisplay ("Sector: SeqNO = {SeqNO}, BookingClass = {BookingClass}")]
Public class Sector
{
Public int SeqNO {get; set ;}
Public string BookingClass {get; set ;}
Public Sector Clone ()
{
Return this. MemberwiseClone () as Sector;
}
}
}