Have you ever tried to combines sequences in order to build Cartesian products in LINQ ? This is really easily achieved using the query expressions syntax, writing for instance :
var ints = Enumerable.Range(1, 4);
var longs = Enumerable.Range(1, 3).Select(i => (long)i);
var products = from i in ints
from l in longs
select i * l;
When I write LINQ queries, I tend to use more often the fluent syntax, as it is more powerful, and allows me to use a wider range of operators. I also try not to mix both syntaxes, because I find it quite confusing. When I want to perform, inside of a more complex query, a simple cross-product as the previous one, the “fluent” equivalent syntax is the following :
var products = ints.SelectMany(i => longs.Select(l => i * l));
In fact, this syntax works very well, but I don’t find it as expressive as the first one. And if you go one step further and add a third sequence to the party…
var ints = Enumerable.Range(1, 4);
var longs = Enumerable.Range(1, 3).Select(i => (long)i);
var strings = new[] { "a", "b", "c" };
var classic = from i in ints
from l in longs
from s in strings
select (i * l).ToString() + s;
The “fluent” syntax gets even more confusing (at least to me) :
var fluent = ints.SelectMany(
i => longs.SelectMany(
l => strings.Select(s => (i * l).ToString() + s)));
I think that what bothers me might be the ever-increasing number of unclosed parenthesis… Anyway, as usual, I played with extensions methods and here is what I came up with, using a new “Cross” method, for the 2 sequences cross-product :
var results = ints
.Cross(longs)
.Select((i, l) => i * l);
And the same syntax for the 3 sequences cross product :
var results = ints
.Cross(longs)
.Cross(strings)
.Select((i, l, s) => (i * l).ToString() + s);
Don’t you find it more expressive ?
Finally, here are the extensions methods implementations :
public static IEnumerable<Tuple<TLeft, TRight>> Cross<TLeft, TRight>(
this IEnumerable<TLeft> left, IEnumerable<TRight> right)
{
return left.SelectMany(l => right.Select(r => Tuple.Create(l, r)));
}
public static IEnumerable<Tuple<TLeft1, TLeft2, TRight>> Cross<TLeft1, TLeft2, TRight>(
this IEnumerable<Tuple<TLeft1, TLeft2>> left, IEnumerable<TRight> right)
{
return left.SelectMany(l => right.Select(r => Tuple.Create(l.Item1, l.Item2, r)));
}
public static IEnumerable<TResult> Select<T1, T2, TResult>(
this IEnumerable<Tuple<T1, T2>> source, Func<T1, T2, TResult> selector)
{
return source.Select(t => selector(t.Item1, t.Item2));
}
public static IEnumerable<TResult> Select<T1, T2, T3, TResult>(
this IEnumerable<Tuple<T1, T2, T3>> source, Func<T1, T2, T3, TResult> selector)
{
return source.Select(t => selector(t.Item1, t.Item2, t.Item3));
}
I must admit that those generic methods signatures are horrible, though…

