计算一组n组的连接集

时间:2010-06-10 12:02:03

标签: c# .net algorithm

好的 - 我甚至不确定这个词是否正确 - 而且我确定被绑定成为一个术语 - 但我会尽力解释。这不是一个十字架产品,结果的顺序绝对至关重要。

假设:

IEnumerable<IEnumerable<string>> sets = 
      new[] { 
              /* a */ new[] { "a", "b", "c" },
              /* b */ new[] { "1", "2", "3" },
              /* c */ new[] { "x", "y", "z" }
            };

其中每个内部可枚举表示生成一组连接的指令,如下所示(此处的顺序很重要):

set a* = new string[] { "abc", "ab", "a" };
set b* = new string[] { "123", "12", "1" };
set c* = new string[] { "xyz", "xy", "x" };

我想按如下方式生成有序连接:

set final = new string { a*[0] + b*[0] + c*[0], /* abc123xyz */
                         a*[0] + b*[0] + c*[1], /* abc123xy  */
                         a*[0] + b*[0] + c*[2], /* abc123x   */
                         a*[0] + b*[0],         /* abc123    */
                         a*[0] + b*[1] + c*[0], /* abc12xyz  */
                         a*[0] + b*[1] + c*[1], /* abc12xy   */
                         a*[0] + b*[1] + c*[2], /* abc12x    */
                         a*[0] + b*[1],         /* abc12     */
                         a*[0] + b*[2] + c*[0], /* abc1xyz   */
                         a*[0] + b*[2] + c*[1], /* abc1xy    */
                         a*[0] + b*[2] + c*[2], /* abc1x     */
                         a*[0] + b*[2],         /* abc1      */
                         a*[0],                 /* abc       */
                         a*[1] + b*[0] + c*[0], /* ab123xyz  */

                         /* and so on for a*[1] */
                         /* ... */

                         a*[2] + b*[0] + c*[0], /* a123xyz   */

                         /* and so on for a*[2] */
                         /* ... */

                         /* now lop off a[*] and start with b + c */

                         b*[0] + c*[0],         /* 123xyz    */

                         /* rest of the combinations of b + c
                            with b on its own as well */

                         /* then finally */
                         c[0],
                         c[1],
                         c[2]};

很明显,会有很多组合!

我可以看到与数字基础的相似之处(因为顺序也很重要),我确信这里也存在排列/组合。

问题是 - 如何编写这样的算法来处理任意数量的字符串集? Linq,非Linq;我没有被打扰。

我为什么要这样做?

确实,为什么!?

在Asp.Net MVC中 - 我想要为部分后端/前端文化和语言组合重新定义部分视图。其中最基本的是,对于给定的基本视图View,我们可以按顺序View-en-GBView-enView-GBView优先(当然认识到语言/文化代码可能是相同的,所以某些组合可能是相同的 - Distinct()将解决这个问题。)

但我也有其他观点,在文化被考虑之前,它们本身还有其他可能的组合(太长时间不能进入 - 但事实是,这个算法将使一大堆真正< / em>很酷,我想为我的开发人员提供!)。

我想生成一个包含所有可接受视图名称的搜索列表,遍历整个批次,直到找到最具体的匹配(由此算法产生这些连接的顺序控制)然后提供已解决的部分视图。

稍后可以缓存搜索结果,以避免一直运行算法的费用。

我已经有了这个工作的真正基本版本,只有一个可枚举的字符串。但这是一个完全不同的海鲜水壶!

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:3)

这是我的尝试:

void Main()
{
    IEnumerable<IEnumerable<string>> sets = 
          new[] { 
                  /* a */ new[] { "a", "b", "c" },
                  /* b */ new[] { "1", "2", "3" },
                  /* c */ new[] { "x", "y", "z" }
                };

    var setCombinations = from set in sets
                          select (from itemLength in Enumerable.Range(1, set.Count()).Reverse()
                                  select string.Concat(set.Take(itemLength).ToArray()));

    IEnumerable<string> result = new[] { string.Empty };

    foreach (var list in setCombinations) {
        result = GetCombinations(result, list);
    }
    // do something with the result
}

IEnumerable<string> GetCombinations(IEnumerable<string> root, IEnumerable<string> append) {
    return from baseString in root
           from combination in ((from str in append select baseString + str).Concat(new [] { baseString }))
           select combination;
}

答案 1 :(得分:2)

这应该产生你想要的东西:

using System;
using System.Linq;
using System.Collections.Generic;

namespace SO3014119
{
    class Program
    {
        private static IEnumerable<string> GetStringCombinations(
            string prefix, 
            IEnumerable<string>[] collections, int startWithIndex)
        {
            foreach (var element in collections[startWithIndex])
            {
                if (startWithIndex < collections.Length - 1)
                {
                    foreach (var restCombination in
                        GetStringCombinations(prefix + element, collections,
                            startWithIndex + 1))
                    {
                        yield return restCombination;
                    }
                }

                yield return prefix + element;
            }
        }

        public static IEnumerable<string> GetStringCombinations(
            params IEnumerable<string>[] collections)
        {
            while (collections.Length > 0)
            {
                foreach (var comb in GetStringCombinations("", collections, 0))
                    yield return comb;

                // "lop off" head and iterate
                collections = collections.Skip(1).ToArray();
            }
        }

        static void Main(string[] args)
        {
            var a = new string[] { "a1", "a2", "a3" };
            var b = new string[] { "b1", "b2", "b3" };
            var c = new string[] { "c1", "c2", "c3" };

            foreach (string combination in GetStringCombinations(a, b, c))
            {
                Console.Out.WriteLine(combination);
            }
        }
    }
}

这会产生(通知我更改了输入集合中的条目,以便更容易看到它们的组合方式):

a1b1c1
a1b1c2
a1b1c3
a1b1
a1b2c1
a1b2c2
a1b2c3
a1b2
a1b3c1
a1b3c2
a1b3c3
a1b3
a1
a2b1c1
a2b1c2
a2b1c3
a2b1
a2b2c1
a2b2c2
a2b2c3
a2b2
a2b3c1
a2b3c2
a2b3c3
a2b3
a2
a3b1c1
a3b1c2
a3b1c3
a3b1
a3b2c1
a3b2c2
a3b2c3
a3b2
a3b3c1
a3b3c2
a3b3c3
a3b3
a3
b1c1
b1c2
b1c3
b1
b2c1
b2c2
b2c3
b2
b3c1
b3c2
b3c3
b3
c1
c2
c3

答案 2 :(得分:1)

解决方案似乎很简单(算法)

在每个数组的末尾添加一个extry空字符串a *,b *,c *

string[] a* = { "abc","ab","a","" };
string[] b* = { "123","12","1","" };
string[] c* = { "xyz","xy","x","" };

List<string> final = new List<string>();

现在就三个阵列发布消息

foreach(string aMember in a*)
foreach(string bMember in b*)
foreach(string cMember in c*)
final.add(aMember+bMember+cMember);

*,b *和c *末尾的额外空字符串将按所需顺序生成特殊字符串,如[0](= a [0] + b [3] + c [3]) 。

编辑:此代码将生成一些额外的字符串。见下面的评论。