Quelind Kajiura
Quelind Kajiura

Reputation: 43

How to rewrite cartesian product with LINQ

I have three functions, one generates cartesian product with loops from 2 arrays, other one with loops from 3 arrays, and one with LINQ with 2 arrays. I want to write a LINQ solution to get it with 3 arrays.

        private static string[][] CartesianProductSmart(string[] arr1, string[] arr2)
        {
            // for each s1 in arr1, extract arr2, 
            // then pass s1 and s2 into a newly-made string array.
            return arr1.SelectMany(s1 => arr2, (s1, s2) => new string[] { s1, s2 })
                .ToArray();
        }
        private static string[][] CartesianProductDumb(string[] arr1, string[] arr2)
        {
            // the dumb way; nested foreach
            string[][] combos = new string[arr1.Length * arr2.Length][];

            int ii = 0;
            foreach (var strOne in arr1)
            {
                foreach (var strTwo in arr2)
                {
                    string[] combo = new string[2];

                    combo[0] = strOne;
                    combo[1] = strTwo;
                    combos[ii] = combo;

                    ii++;
                }
            }
            return combos;
        }
        private static string[][] CartesianProductDumbX3(string[] arr1, string[] arr2, string[] arr3)
        {
            // the dumb way; nested foreach
            string[][] combos = new string[arr1.Length * arr2.Length * arr3.Length][];

            int ii = 0;
            foreach (var strOne in arr1)
            {
                foreach (var strTwo in arr2)
                {
                    foreach (var strThree in arr3)
                    {
                        string[] combo = new string[3];

                        combo[0] = strOne;
                        combo[1] = strTwo;
                        combo[2] = strThree;
                        combos[ii] = combo;

                        ii++;
                    }
                }
            }

            return combos;
        }

The first two functions behave identically - they both return a cartesian product of 2 arrays. The third one does it with three arrays, how can I rewrite that function with LINQ? (Ultimately I want to write it so that I can give it any array number, but just 3 is good enough for now).

Upvotes: 0

Views: 388

Answers (1)

Rufus L
Rufus L

Reputation: 37020

I'm not sure if this is what you're looking for, but it seems the simplest and most readable to me:

private static string[][] CartesianProductLinq(string[] arr1, string[] arr2,
    string[] arr3)
{
    return (from s1 in arr1
        from s2 in arr2
        from s3 in arr3
        select new[] {s1, s2, s3}).ToArray();
}

If you prefer the method-chain syntax, it might look something like:

private static string[][] CartesianProductLinq(string[] arr1, string[] arr2, 
    string[] arr3)
{
    return arr1
        .SelectMany(s1 => arr2, (s1, s2) => new {s1, s2})
        .SelectMany(result => arr3, (result, s3) => new[] {result.s1, result.s2, s3})
        .ToArray();
}

Note the method names have been changed, since Linq is not inherently "smart", nor are loops inherently "dumb" (loops may be more efficient in some circumstances)

Upvotes: 2

Related Questions