Generating a n-ary Cartesian product example

旧街凉风 提交于 2020-01-20 06:58:27

问题


I found that Eric Lippert's post here suits a particular problem I have.

The problem is I can't wrap my head around how I should be using it with a 2+ amount of collections.

Having

var collections = new List<List<MyType>>();
foreach(var item in somequery)
{
    collections.Add(
            new List<MyType> { new MyType { Id = 1} .. n }
        );
}

How do I apply the cartesian product linq query on the collections variabile ?

The extension method is this one:

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})                       
        );
 }

Here is Eric's example for 2 collections:

var arr1 = new[] {"a", "b", "c"};
var arr2 = new[] { 3, 2, 4 };
var result = from cpLine in CartesianProduct(
                     from count in arr2 select Enumerable.Range(1, count)) 
             select cpLine.Zip(arr1, (x1, x2) => x2 + x1);

回答1:


The sample code is already able to do "n" cartesian products (it does 3 in the example). Your problem is that you have a List<List<MyType>> when you need an IEnumerable<IEnumerable<MyType>>

IEnumerable<IEnumerable<MyType>> result = collections
  .Select(list => list.AsEnumerable())
  .CartesianProduct();



回答2:


Since List<T> is IEnumerable<T>, then your problem using Eric's solution is solved as follows:

var collections = new List<List<MyType>>();
var product =  collections.CartesianProduct();
foreach(var collection in product)
{
    // a single collection of MyType items
    foreach(var item in collection)
    {
        // each item of type MyType within a collection
        Console.Write(item);
    }    
}

Of course you can aggregate the items from each collection in a more concise manner, for example as a single string:

var product = 
    collections
    .CartesianProduct()
    .Select(xs => xs.Aggregate(new StringBuilder(), (sb, x) => sb.Append(x.ToString()), sb => sb.ToString()));

foreach(var collectionAsString in product)
{
    Console.WriteLine(collectionAsString);
}


来源:https://stackoverflow.com/questions/13647662/generating-a-n-ary-cartesian-product-example

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!