Reputation: 2874
I would like to build a method or extension method that takes multiple lists and combines them in the following way:
Lets say i have two lists:
int[] list1 = {3, 1, 2};
int[] list2 = {5, 4 };
I would expect a list of arrays as a result like this:
[1,4]
[1,5]
[2,4]
[2,5]
[3,4]
[3,5]
The number of columns in my resulting list of arrays would be determined by the amount of lists passed and both columns need to be sorted. The number of rows is just the (length of list A) * (length of list B) * (length of list N)
In this example is 3 * 2 = 6 rows. 2 columns (because 2 input lists).
What would be an elegant way of doing this with linq?
Thanks!
Upvotes: 1
Views: 1426
Reputation: 2874
Credit goes here to @Jon for pointing me to the right source and @EricLippert for his clever solution:
public 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 }));
}
http://ericlippert.com/2010/06/28/computing-a-cartesian-product-with-linq/
Works nice with ints and strings:
string[] list1 = {"1", "2", "3"};
string[] list2 = { "4","5" };
var lists = new List<string[]>(){list1,list2};
var result = lists.CartesianProduct();
Upvotes: 2
Reputation: 30698
Try cross join
int[] list1 = {3, 1, 2};
int[] list2 = {5, 4 };
var result = (from l1 in list1
from l2 in list2
select new [] {l1, l2}).ToList()
Upvotes: 3
Reputation: 437376
Use SelectMany
:
var combinations = list1.SelectMany(i1 => list2.Select(i2 => new[] { i1, i2 }));
or if you prefer
var combinations = list1.SelectMany(i1 => list2, (i1, i2) => new[] { i1, i2 });
If you want to get the results in a specific order you can follow this up with OrderBy
etc.
Upvotes: 2