1

I am trying to figure out how to create a single concatenated list using C#, originating from 3 separate lists. For example:

 List 1: Ugly, Pretty
 List 2: Dogs, Carts, Pigs
 List 3: Rock, Suck

Output:

 Ugly Dogs Rock
 Ugly Dogs Suck
 Ugly Cats Rock
 Ugly Cats Suck
 Ugly Pigs Rock
 Ugly Pigs Suck
 Pretty Dogs Rock
 Pretty Dogs Suck
 Pretty Cats Rock
 Pretty Cats Suck
 Pretty Pigs Rock
 Pretty Pigs Suck

I know it is just nested loops, but the part I cant figure out is how to use List-strings for each list.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Jeagr
  • 1,038
  • 6
  • 16
  • 30

3 Answers3

4

Isn't it a Cartesian product?

var r = from i1 in list1
        from i2 in list2
        from i3 in list3
        select new { i1, i2, i3 };
        // or String.Format("{0} {1} {2}", i1, i2, i3);
abatishchev
  • 98,240
  • 88
  • 296
  • 433
4
var list = from s1 in list1
           from s2 in list2
           from s3 in list3
           select s1 + " " + s2 + " " + s3;
Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
  • I'd recommend use something else in select statement because currently you have excess concatenation thus memory use. – abatishchev Dec 16 '12 at 22:22
  • 1
    @abatishchev actually there will not be issues. When you are concatenating 2 or 3 strings, then compiler generates call to `String.Concat(str1, str2, str3)`, which uses `FastAllocateString` to create new string. This is even more efficient, than creating new `StringBuilder` inside `String.Format` call. But in this particular case OP want to have space-separated string, so this is the reason why format should be used. – Sergey Berezovskiy Dec 16 '12 at 22:31
  • @lazyberezovsky - I thought the same thing and tested it: concatenating it with `a + " " + b + " " + c` is about 30% faster than `String.Format`. – JulianR Dec 16 '12 at 22:36
  • @LazyBerezovsky: Don't insist that format is better, much probably it is not. Just general case where string concatenation (both your and my snippets) aren't efficient. – abatishchev Dec 16 '12 at 22:37
  • @abatishchev agree, but performance (comparing Format and concatenation) will not suffer in this case (readability will suffer, I like Format better) – Sergey Berezovskiy Dec 16 '12 at 22:42
  • @JulianR: I would launch enumeration separately about 1-10k times and then calculate average time for each of the methods under measurement. – abatishchev Dec 16 '12 at 23:32
3
List<string> list1 = new List<string>(){ "Ugly", "Pretty"};
List<string> list2 = new List<string>(){ "Dogs", "Carts", "Pigs"};
List<string> list3 = new List<string>(){ "Rock", "Suck"};

var result = from s1 in list1
             from s2 in list2
             from s3 in list3
             select new[] { s1, s2, s3 };

foreach (var item in result)
{
    Console.WriteLine(String.Join(",", item));
}

If you are looking for a more general solution, not only for 3 lists you may try Eric Lippert's solution

foreach (var item in new[] { list1, list2, list3 }.CartesianProduct())
{
    Console.WriteLine(String.Join(",", item));
}

public static partial class MyExtensions
{
    // Eric Lippert’s Blog
    // Computing a Cartesian Product with LINQ
    // http://blogs.msdn.com/b/ericlippert/archive/2010/06/28/computing-a-cartesian-product-with-linq.aspx
    public 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;
    }
}
L.B
  • 114,136
  • 19
  • 178
  • 224
  • L.B. - So, if i wanted the results to go to a new list and be printed to a new textbox, would I do something like this? textBox_MergeListResults.Text = string.Join("\r\n", WHAT GOES HERE?); – Jeagr Dec 16 '12 at 22:31
  • @Jeagr `textBox_MergeListResults.Text = String.Join(Environment.NewLine, result.Select(x=> String.Join(",", x)));` – L.B Dec 16 '12 at 22:38
  • For some reason, when I copy the text to the clipboard, the result is wrong...any ideas? The textbox show everything ok, but the pasted text shows each item on its own line...like the "\n" isn't copying over to the clipboard. – Jeagr Dec 17 '12 at 01:07
  • @Jeagr Do you really think your copy/paste problem is related with your question? – L.B Dec 17 '12 at 07:31