0

我有一个字符串 [] 数组的通用列表,我需要构建一个字符串列表,其中包含这些数组中项目的所有可能组合。我很难理解最好的方法。

所以:列表 mylist = 新列表;// 然后我从数据库中填充它...

mylist 的内容如下所示:

Buildings ||| Facilities ||| Fields ||| Files; Groups; Entity; ||| Controllers; FX; Steam;

管道“|||”分隔 mylist 中的每个字符串数组,分号是表示每个数组中的项目的分隔符。所以数组的最小长度为 1,最大为 N。我需要构建一个连字符“---”分隔的字符串列表,其中包含上述所有可能的组合,但要保持它们在列表。所以以上面的例子为例,我会想出这个字符串列表:

Buildings---Facilities---fields---Files---Controllers
Buildings---Facilities---fields---Groups---Controllers
Buildings---Facilities---fields---Entity---Controllers

Buildings---Facilities---fields---Files---Fx
Buildings---Facilities---fields---Groups---Fx
Buildings---Facilities---fields---Entity---Fx

Buildings---Facilities---fields---Files---Steam
Buildings---Facilities---fields---Groups---Steam
Buildings---Facilities---fields---Entity---Steam

如果列表中的第三个数组有 2 个项目,而不是 1(“字段”) - 我们将有一个 18 个字符串的列表,而不是 9 个(3x3x2)。

我尝试使用 for 循环,知道哪个数组的长度最大,然后循环遍历每个列表项,但我就是无法让它工作。睡在上面真的没有帮助。

任何人?

4

3 回答 3

2

我会尝试递归:

private void button1_Click(object sender, EventArgs e)
        {
            List<string[]> strs = new List<string[]>();
            strs.Add(new string[] {"Buildings"});
            strs.Add(new string[] {"Facilities"});
            strs.Add(new string[] {"Fields"});
            strs.Add(new string[] {"Files", "Groups", "Entity"});
            strs.Add(new string[] {"Controllers", "FX", "Steam"});
            List<string> list = AddStringsToList(strs, 0);

        }

        List<string> AddStringsToList(List<string[]> list, int level)
        {
            List<string> listOfStrings = new List<string>();
            if (level == list.Count - 1)
            {
                foreach (string s in list[level])
                {
                    listOfStrings.Add(s);
                }
            }
            else if(level<list.Count-1)
            {
                List<string> list1 = AddStringsToList(list, level + 1);
                foreach (string s in list[level])
                {
                    foreach(string s1 in list1)
                        listOfStrings.Add(s + "---" + s1);
                }
            }
            return listOfStrings;
        }

经过测试,它可以工作!

于 2012-10-26T15:53:18.037 回答
2

我认为这可能会满足您的需求:

static IEnumerable<string> Combinations(IEnumerable<IEnumerable<string>> items)
{
    return items.Aggregate((outs, ins) => outs.SelectMany(o => ins.Select(i => o + "---" + i)));
}

这是一个示例用法

static void Main(string[] args)
{
    IEnumerable<IEnumerable<string>> items = new string[][]
    {
        new [] { "Buildings" },
        new [] { "Facilities" },
        new [] { "Fields" },
        new [] { "Files", "Groups", "Entity" },
        new [] { "Controllers", "FX", "Steam" }
    };

    foreach (var c in Combinations(items))
        Console.WriteLine(c);

    Console.ReadLine();
}

对于每组可能性,它会采用它目前拥有的所有字符串(例如“建筑物---设施---字段---文件”、“建筑物---设施---字段---实体”等),然后对于每种可能性(例如 {“Controllers”、“FX”、“Steam”}),它将该可能性附加到输出字符串以获得一组新的输出字符串。聚合迭代此过程,仅从第一个元素作为输出字符串的可能性开始,然后连续重复此“笛卡尔积”,直到消耗完所有输入。

编辑

作为参考,这是示例程序的输出:

Buildings---Facilities---Fields---Files---Controllers
Buildings---Facilities---Fields---Files---FX
Buildings---Facilities---Fields---Files---Steam
Buildings---Facilities---Fields---Groups---Controllers
Buildings---Facilities---Fields---Groups---FX
Buildings---Facilities---Fields---Groups---Steam
Buildings---Facilities---Fields---Entity---Controllers
Buildings---Facilities---Fields---Entity---FX
Buildings---Facilities---Fields---Entity---Steam

我想指出,这个解决方案非常有效。它不使用递归,这使得它对于长链的情况特别有效。此外,它会延迟评估结果,如果您要处理许多结果组合,则内存效率会更高(请记住,这些组合会随着链长呈指数增长)。

于 2012-10-26T16:21:17.977 回答
0

让我们生成这个:

Buildings---Facilities---fields---Files---Controllers
Buildings---Facilities---fields---Files---Fx
Buildings---Facilities---fields---Files---Steam

Buildings---Facilities---fields---Groups---Controllers
Buildings---Facilities---fields---Groups---Fx
Buildings---Facilities---fields---Groups---Steam

Buildings---Facilities---fields---Entity---Controllers
Buildings---Facilities---fields---Entity---Fx
Buildings---Facilities---fields---Entity---Steam

首先,我们假设数据库中的数据是这种格式:

List<List<string>> dataFromDb;

一些内部集合是否只有一个值并不重要。然后像这样的东西应该可以解决问题:

void ConcatString(string prefix, int index, List<List<string>> collection, List<string> output)
{
    if(index == collection.Count)
    {
        output.Add(prefix);
        return;
    }
    var subCollection = collection[index];
    foreach(var str in subCollection)
    {
        string newPrefix = ((prefix.Length > 0)? "---" : "") + str;
        ConcatString(newPrefix, index+1, collection, output);
    }
}

像这样调用:

var output = new List<string>();
ConcatString("", 0, dataFromDb, output);

您要查找的列表应该在输出中。现在,请注意,我还没有运行它(哎呀,我什至没有编译它)所以你需要调试它,但它至少应该让你朝着正确的方向前进。

于 2012-10-26T15:50:03.860 回答