8

I have a table of categories:

 Catid | Desciption
 1 | Color
 2 | Size
 3 | Material

And a table of category items

 Catid | Name
 1 | Red
 1 | Blue
 1 | Green
 2 | Small
 2 | Med
 2 l Large
 3 | Cotton
 3 | Silk

I need to loop through all the items and display them in a labels like this:

 Red Small Cotton
 Red Small Silk
 Red Med Cotton
 Red Med Silk
 Red Large Cotton
 Red Large Silk
 Blue Small Cotton
 Blue Small Silk
 Blue Med Cotton
 Blue Med Silk
 Blue Large Cotton
 Blue Large Silk
 Green Small Cotton
 Green Small Silk
 Green Med Cotton
 Green Med Silk
 Green Large Cotton
 Green Large Silk

Please note: There could be more or less categories. It is not predetermined.

Any suggestions? Thank you

vts
  • 1,647
  • 2
  • 16
  • 18
  • 1
    Please note: There could be more or less categories. It is not predetermined. – vts May 09 '12 at 16:03

2 Answers2

21
var result = list.GroupBy(t => t.Id).CartesianProduct();

using the CartesianProduct Extension Method from Eric Lippert's Blog:

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

Example:

var list = new[]
{
    new { Id = 1, Description = "Red"    },
    new { Id = 1, Description = "Blue"   },
    new { Id = 1, Description = "Green"  },
    new { Id = 2, Description = "Small"  },
    new { Id = 2, Description = "Med"    },
    new { Id = 2, Description = "Large"  },
    new { Id = 3, Description = "Cotton" },
    new { Id = 3, Description = "Silk"   },
};

var result = list.GroupBy(t => t.Id).CartesianProduct();

foreach (var item in result)
{
    Console.WriteLine(string.Join(" ", item.Select(x => x.Description)));
}

Output:

Red Small Cotton
Red Small Silk
Red Med Cotton
Red Med Silk
Red Large Cotton
Red Large Silk
Blue Small Cotton
Blue Small Silk
Blue Med Cotton
Blue Med Silk
Blue Large Cotton
Blue Large Silk
Green Small Cotton
Green Small Silk
Green Med Cotton
Green Med Silk
Green Large Cotton
Green Large Silk
dtb
  • 213,145
  • 36
  • 401
  • 431
  • 3
    I was just writing this answer up, +1 from me for being the first person to actually answer the question – Lukazoid May 09 '12 at 16:07
  • Thank you. This almost work. But I get these results too: Red, Blue, Green, Red Small Red Med Red Large Blue Small, Blue Med, Blue Large, Green Small, Green Med, Green Large, Any ideas on how to remove those combinations? – vts May 09 '12 at 17:21
  • @user1095952: I do not get these results; my example program gives the output as shown above. Show your code. – dtb May 09 '12 at 17:25
  • New blog link: https://ericlippert.com/2010/06/28/computing-a-cartesian-product-with-linq/ – BlueSky Nov 24 '20 at 23:38
17

Try using a cross join:

var combo = from l1 in List1
            from l2 in List2
            select new {l1, l2};
mfluehr
  • 2,832
  • 2
  • 23
  • 31
Pranay Rana
  • 175,020
  • 35
  • 237
  • 263
  • 2
    On a mathy note that the question asker might find interesting: A cross join is essentially a Cartesian product (which is combining all elements from set A with all elements from set B in unique pairs). – Corbin May 09 '12 at 16:02