Generate all Combinations from Multiple (n) Lists

Hope this helps.

class NListBuilder

{
    Dictionary<int, List<string>> tags = new Dictionary<int, List<string>>();

    public NListBuilder()
    {
        tags.Add(1, new List<string>() { "A", "B", "C" });
        tags.Add(2, new List<string>() { "+", "-", "*" });
        tags.Add(3, new List<string>() { "1", "2", "3" });
    }

    public List<string> AllCombos
    {
        get
        {
            return GetCombos(tags);
        }
    }

    List<string> GetCombos(IEnumerable<KeyValuePair<int, List<string>>> remainingTags)
    {
        if (remainingTags.Count() == 1)
        {
            return remainingTags.First().Value;
        }
        else
        {
            var current = remainingTags.First();
            List<string> outputs = new List<string>();
            List<string> combos = GetCombos(remainingTags.Where(tag => tag.Key != current.Key));

            foreach (var tagPart in current.Value)
            {
                foreach (var combo in combos)
                {
                    outputs.Add(tagPart + combo);
                }
            }

            return outputs;
        }


    }
}

Here is a simple non-recursive solution that just concatenates the elements of each combination:

public static List<string> GetAllPossibleCombos(List<List<string>> strings)
{
    IEnumerable<string> combos = new [] { "" };

    foreach (var inner in strings)
        combos = from c in combos
                 from i in inner
                 select c + i;

    return combos.ToList();
}

static void Main(string[] args)
{
    var x = GetAllPossibleCombos(
        new List<List<string>>{
            new List<string> { "a", "b", "c" },
            new List<string> { "x", "y" },
            new List<string> { "1", "2", "3", "4" }});
}

You could generalize this to return an IEnumerable<IEnumerable<string>>, which allows the caller to apply any operation they like for transforming each combination into a string (such as the string.Join below). The combinations are enumerated using deferred execution.

public static IEnumerable<IEnumerable<string>> GetAllPossibleCombos(
    IEnumerable<IEnumerable<string>> strings)
{
    IEnumerable<IEnumerable<string>> combos = new string[][] { new string[0] };

    foreach (var inner in strings)
        combos = from c in combos
                 from i in inner
                 select c.Append(i);

    return combos;
}

public static IEnumerable<TSource> Append<TSource>(
    this IEnumerable<TSource> source, TSource item)
{
    foreach (TSource element in source)
        yield return element;

    yield return item;
}

static void Main(string[] args)
{
    var combos = GetAllPossibleCombos(
        new List<List<string>>{
            new List<string> { "a", "b", "c" },
            new List<string> { "x", "y" },
            new List<string> { "1", "2", "3", "4" }});

    var result = combos.Select(c => string.Join(",", c)).ToList();
}