从多个(n)列表生成所有组合

时间:2015-09-14 18:02:45

标签: c# linq list dictionary

编辑:我完全重做了我的问题,因为我已经找到了最简单的问题。感谢到目前为止的评论者让我思考根本问题。

public List<string> GetAllPossibleCombos(List<List<string>> strings)
{
    List<string> PossibleCombos = new List<string>();

    //????
    {
        string combo = string.Empty;
        // ????
        {
            combo += ????
        }
        PossibleCombos.Add(combo);
    }

    return PossibleCombos;
}

我需要弄清楚如何递归遍历每个List<string>并将每个列表中的1个字符串组合成一个组合string。不要过于担心格式化字符串,因为“实时”代码使用自定义对象。此外,请随意假设每个列表至少包含1个字符串,并且没有空值。

5 个答案:

答案 0 :(得分:5)

希望这有帮助。

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


    }
}

答案 1 :(得分:5)

这是一个简单的非递归解决方案,它只是连接每个组合的元素:

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

您可以对此进行概括以返回IEnumerable<IEnumerable<string>>,这允许调用者将他们喜欢的任何操作应用于将每个组合转换为字符串(例如下面的string.Join)。使用延迟执行枚举组合。

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

答案 2 :(得分:5)

以防万一,这是道格拉斯GetAllPossibleCombos方法的方法语法版本。

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

     foreach (var inner in strings)
     {
         combos = combos.SelectMany(r => inner.Select(x => r + x));
     }

     return combos.ToList();
 }

答案 3 :(得分:3)

这是适用于所有对象类型的通用版本:

    public static List<List<T>> GetAllPossibleCombos<T>(List<List<T>> objects)
    {
        IEnumerable<List<T>> combos = new List<List<T>>() { new List<T>() };

        foreach (var inner in objects)
        {
            combos = combos.SelectMany(r => inner
            .Select(x => {
                var n = r.DeepClone();
                if (x != null)
                {
                    n.Add(x);
                }
                return n;
            }).ToList());
        }

        // Remove combinations were all items are empty
        return combos.Where(c => c.Count > 0).ToList();
    }

如果您提供空值,它也会给您空组合。例如:

        var list1 = new List<string>() { "1A", "1B", null };
        var list2 = new List<string>() { "2A", "2B", null };
        var output = GetAllPossibleCombos(allLists);

将包含:

[[“ 1A”],[“ 1B”],[“ 2A”],[“ 2B”],[“ 1A”,“ 2A”],[“ 1A”,“ 2B”],[“ 1B“,” 2A“],[” 1B,“” 2B“]]

不只是:

        var list1 = new List<string>() { "1A", "1B" };
        var list2 = new List<string>() { "2A", "2B" };
        var output = GetAllPossibleCombos(allLists);

[[“” 1A“,” 2A“],[” 1A“,” 2B“],[” 1B“,” 2A“],[” 1B,“ 2B”]]

注意: DeepClone 是用于复制列表的扩展方法。这可以通过多种方式完成

    public static T DeepClone<T>(this T source)
    {
        // Don't serialize a null object, simply return the default for that object
        if (Object.ReferenceEquals(source, null))
        {
            return default(T);
        }

        var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };

        return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);

    }

答案 4 :(得分:1)

以下是适用于任何泛型类型的答案,还带有将base-10转换为base-n的功能。

public static class IntExt
{
    const string Symbols = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    public static string ToString(this int value, int toBase)
    {
        switch (toBase)
        {
            case 2:
            case 8:
            case 10:
            case 16:
                return Convert.ToString(value, toBase);

            case 64:
                return Convert.ToBase64String(BitConverter.GetBytes(value));

            default:
                if (toBase < 2 || toBase > Symbols.Length)
                    throw new ArgumentOutOfRangeException(nameof(toBase));

                if (value < 0)
                    throw new ArgumentOutOfRangeException(nameof(value));

                int resultLength = 1 + (int)Math.Max(Math.Log(value, toBase), 0);
                char[] results = new char[resultLength];
                int num = value;
                int index = resultLength - 1;
                do
                {
                    results[index--] = Symbols[num % toBase];
                    num /= toBase;
                }
                while (num != 0);

                return new string(results);
        }
    }
}

public class UnitTest1
{
    public static T[][] GetJoinCombinations<T>(T[][] arrs)
    {
        int maxLength = 0;
        int total = 1;
        for (int i = 0; i < arrs.Length; i++)
        {
            T[] arr = arrs[i];
            maxLength = Math.Max(maxLength, arr.Length);
            total *= arr.Length;
        }

        T[][] results = new T[total][];
        int n = 0;
        int count = (int)Math.Pow(maxLength, arrs.Length);
        for (int i = 0; i < count; i++)
        {
            T[] combo = new T[arrs.Length];
            string indices = i.ToString(maxLength).PadLeft(arrs.Length, '0');
            bool skip = false;
            for (int j = 0; j < indices.Length; j++)
            {
                T[] arr = arrs[j];
                int index = int.Parse(indices[j].ToString());
                if (index >= arr.Length)
                {
                    skip = true;
                    break;
                }

                combo[j] = arr[index];
            }

            if (!skip)
                results[n++] = combo;
        }

        return results;
    }

    [Fact]
    public void Test1()
    {
        string[][] results = GetJoinCombinations(new string[][]
        {
            new string[] { "1", "2", "3" },
            new string[] { "A", "B", "C" },
            new string[] { "+", "-", "*", "/" },
        });
    }
}