22

Given lists l1 = {1, 2} and l2 = {4, 5, 6 } I want to get a new list that has elements:

rez = { {1, 4}, {1, 5}, {1, 6}, {2, 4}, {2, 5}, {2, 6} }

Suggestions?

Cristian Diaconescu
  • 34,633
  • 32
  • 143
  • 233

7 Answers7

43

Yes it is possible. Eric Lippert wrote a very good article on this topic:

Computing a Cartesian Product with LINQ

If you only have 2 lists, then you could directly use multiple from like this:

from a in s1 
from b in s2 
select new [] { a, b};

or even:

s1.SelectMany(a => s2.Select(b => new [] { a, b }));

But the solution given by Eric Lippert in the previous article allows you to compute the cartesian product of several sequences. With the following extension method:

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

You could write:

var l1 = new[] {1, 2};
var l2 = new[] {4, 5, 6};
var l3 = new[] {7, 3};

foreach (var result in new []{l1,l2,l3}.CartesianProduct())
{
    Console.WriteLine("{"+string.Join(",",result)+"}");
}

And obtain:

{1,4,7}
{1,4,3}
{1,5,7}
{1,5,3}
{1,6,7}
{1,6,3}
{2,4,7}
{2,4,3}
{2,5,7}
{2,5,3}
{2,6,7}
{2,6,3}
Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
Romain Verdier
  • 12,833
  • 7
  • 57
  • 77
4

Eric Lippert's already done it for you!

http://blogs.msdn.com/b/ericlippert/archive/2010/06/28/computing-a-cartesian-product-with-linq.aspx

you probably just want to the linq fluent syntax of SelectMany

var s1 = new[] {a, b}; 
var s2 = new[] {x, y, z}; 


var product = 
from first in s1 
from second in s2 
select new[] { first, second };

product.SelectMany(o=>o);

or Eric's blog post version

static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences) 
{ 
  // base case: 
  IEnumerable<IEnumerable<T>> result = new[] { Enumerable.Empty<T>() }; 
  foreach(var sequence in sequences) 
  { 
    var s = sequence; // don't close over the loop variable 
    // recursive case: use SelectMany to build the new product out of the     old one 
    result = 
      from seq in result 
      from item in s 
      select seq.Concat(new[] {item}); 
  } 
  return result; 
}

product.CartesianProduct();

BozoJoe
  • 6,117
  • 4
  • 44
  • 66
Graham Clark
  • 12,886
  • 8
  • 50
  • 82
3
var result = from a in l1
             from b in l2
             select new[] { a, b }
Justin Niessner
  • 242,243
  • 40
  • 408
  • 536
2

Here you go;

var rez =  from first in l1 
           from second in l2 
           select new[] { first, second };
Greg
  • 23,155
  • 11
  • 57
  • 79
NetSide
  • 3,849
  • 8
  • 30
  • 41
2

Great article by Eric Lippert - see links in other answers. What's even better, this was the first try I did before looking at the answers on this page :)

In short:

var rez = 
    from e1 in l1
    from e2 in l2 
    select new {e1, e2};
Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
Cristian Diaconescu
  • 34,633
  • 32
  • 143
  • 233
1

something like this will do what you are looking for.

var l1 = new List<int>{1,2};
var l2 = new List<int>{4,5,6};

var p = from n in l1
        from m in l2
        select new { Fst = n, Scd = m };

with this answer your tuples {x,y} are an anonymous type.

cirons42
  • 74
  • 1
  • 3
-3

You want

l1.Join(l2, a => 1, b => 1, (a, b) => new [] { a, b });
Jader Dias
  • 88,211
  • 155
  • 421
  • 625
  • Join is not necessary for this operation and might even create a bit more overhead (don't quote me on that last part). The other answers demonstrate something more intuitive. – Anthony Pegram Aug 26 '10 at 14:17
  • 4
    Sure, it works, but this is a completely unnecessary abuse of the join sequence operator. The purpose of the join sequence operator is to efficiently perform filtering operations on the Cartesian product, but you are using it here to explicitly do *no filtering*. This means that all the mechanisms inside the implementation of Join which are designed to ensure efficient filtering are now working *against* you rather than *for* you. If you want to do a simple unfiltered Cartesian product, we provide the SelectMany sequence operator to do that. *Use the right tool for the job.* – Eric Lippert Aug 26 '10 at 15:28