【问题标题】:Calculate a set of concatenated sets of n sets计算n个集合的连接集合
【发布时间】:2010-06-10 12:02:02
【问题描述】:

好的 - 我什至不确定这个术语是否正确 - 我确信 一定 是这个术语 - 但我会尽力解释。这不是一个交叉产品,结果的顺序是绝对关键的。

给定:

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() 将解决此问题。

但我也有其他观点,在考虑文化之前,它们本身就有其他可能的组合(太长了,无法深入 - 但事实是,这个算法将启用一大堆真的 很酷,我想为我的开发人员提供服务!)。

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

搜索结果可以稍后被缓存以避免一直运行算法的开销。

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

非常感谢任何帮助。

【问题讨论】:

    标签: c# .net algorithm


    【解决方案1】:

    这是我的尝试:

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

    【讨论】:

    • 工作得很好 - 它包含将原始输入数组转换为其连接集的代码 - 非常好,谢谢!
    • 我将其标记为答案主要是因为它代表了从输入数组到输出的完整往返。也因为 Linq 的使用;漂亮:)
    【解决方案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
    

    【讨论】:

    • 感谢您的回答。有趣 - 将复制/粘贴和测试;但是它缺少一些;因为它应该以“a1a2a3b1b2b3c1c2c3”开头,所有 c 都掉下来,然后 'b3' 掉下来,我们再次应用所有 C,令人作呕(字面意思!)
    • 对不起,我只能回答被问的问题,而不是你应该问的问题。您特别列出了您想要的输出,我准确地生成了该输出。如果您想要不同的输出,那么您需要更改问题。
    • 我刚刚在我的原始输入集“abc”、“123”、“xyz”上运行了代码。在问题中,我明确指出第一个条目应该是“abc123xyz”;此代码产生“a1x”。我的示例可能会混淆,因为我使用了 a*[0]、b*[0]、c*[0] - 之前定义为由原始 a、b 和 c 生成的串联数组。不过,我再次感谢您的努力。
    • 啊 - 此代码中唯一缺少的是将 a,b,c;1,2,3;x,y,z 转换为 abc,ab,c;123,12,1 ;xyz,xy,x - 如果我将这些输入到您的算法中,那么它就可以完成工作 - 我所要做的就是首先生成 a* b* 和 c* 数组。很聪明。谢谢!
    【解决方案3】:

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

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

    string[] a* = { "abc","ab","a","" };
    string[] b* = { "123","12","1","" };
    string[] c* = { "xyz","xy","x","" };
    
    List<string> final = new List<string>();
    

    现在对三个数组做一个newsted

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

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

    编辑:这段代码会产生一些额外的字符串。请参阅下面的评论。

    【讨论】:

    • 它也产生a[0]+b[3]+c[0],即。 "abcxyz",结果中没有 b* 值部分。
    • 添加空字符串 - 是的,我意识到这可能是解决方案的一部分,以使其更简单;然而,虽然这个算法可能只适用于三组字符串,但它不能应用于未知数量的字符串组。
    • @Lasse:感谢您指出这个错误。想念它真是太愚蠢了。
    猜你喜欢
    • 1970-01-01
    • 2014-11-19
    • 2013-09-18
    • 2021-02-11
    • 2018-09-15
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 1970-01-01
    相关资源
    最近更新 更多