拆分并连接字符串数据的多个逻辑“分支”

我知道关于排列列表,有几个类似的措辞问题,但他们似乎并没有真正处理我正在寻找的东西。 我知道有办法做到这一点,但我画了一个空白。 我有一个类似于这种格式的平面文件:

Col1|Col2|Col3|Col4|Col5|Col6
a|b,c,d|e|f|g,h|i
. . .

现在有个诀窍:我想创建这些行的所有可能排列的列表,其中行中用逗号分隔的列表表示可能的值。 例如,我应该能够将表示上面的IEnumerable<string>作为行:

IEnumerable<string> row = new string[] { "a", "b,c,d", "e", "f", "g,h", "i" };
IEnumerable<string> permutations = GetPermutations(row, delimiter: "/");

这应该生成以下字符串数据集合:

a/b/e/f/g/i
a/b/e/f/h/i
a/c/e/f/g/i
a/c/e/f/h/i
a/d/e/f/g/i
a/d/e/f/h/i

这对我来说似乎是优雅地融入了递归方法,但显然我周一有一个不好的例子,我不能完全围绕如何处理它。 一些帮助将不胜感激。 GetPermutations(IEnumerable<string>, string)应该是什么样子?


你有我的“递归”。 这是另一个建议:

private IEnumerable<string> GetPermutations(string[] row, string delimiter,
                                            int colIndex = 0, string[] currentPerm = null)
{
    //First-time initialization:
    if (currentPerm == null) { currentPerm = new string[row.Length]; }

    var values = row[colIndex].Split(',');
    foreach (var val in values)
    {
        //Update the current permutation with this column's next possible value..
        currentPerm[colIndex] = val;

        //..and find values for the remaining columns..
        if (colIndex < (row.Length - 1))
        {
            foreach (var perm in GetPermutations(row, delimiter, colIndex + 1, currentPerm))
            {
                yield return perm;
            }
        }
        //..unless we've reached the last column, in which case we create a complete string:
        else
        {
            yield return string.Join(delimiter, currentPerm);
        }
    }
}

我不确定这是否是最优雅的方法,但它可能会让你开始。

private static IEnumerable<string> GetPermutations(IEnumerable<string> row, 
                                                    string delimiter = "|")
{
    var separator = new[] { ',' };
    var permutations = new List<string>();
    foreach (var cell in row)
    {
        var parts = cell.Split(separator);
        var perms = permutations.ToArray();
        permutations.Clear();
        foreach (var part in parts)
        {
            if (perms.Length == 0)
            {
                permutations.Add(part);
                continue;
            }
            foreach (var perm in perms)
            {
                permutations.Add(string.Concat(perm, delimiter, part));
            }
        }
    }
    return permutations;
}

当然,如果排列顺序很重要,最后可以添加一个.OrderBy()

编辑:添加一个alernative

你也可以在确定排列之前通过计算一些数字来建立一个字符串数组列表。

private static IEnumerable<string> GetPermutations(IEnumerable<string> row, 
                                                    string delimiter = "|")
{
    var permutationGroups = row.Select(o => o.Split(new[] { ',' })).ToArray();
    var numberOfGroups = permutationGroups.Length;
    var numberOfPermutations = 
           permutationGroups.Aggregate(1, (current, pg) => current * pg.Length);
    var permutations = new List<string[]>(numberOfPermutations);

    for (var n = 0; n < numberOfPermutations; n++)
    {
        permutations.Add(new string[numberOfGroups]);
    }

    for (var position = 0; position < numberOfGroups; position++)
    {
        var permutationGroup = permutationGroups[position];
        var numberOfCharacters = permutationGroup.Length;
        var numberOfIterations = numberOfPermutations / numberOfCharacters;
        for (var c = 0; c < numberOfCharacters; c++)
        {
            var character = permutationGroup[c];
            for (var i = 0; i < numberOfIterations; i++)
            {
                var index = c + (i * numberOfCharacters);
                permutations[index][position] = character;
            }
        }
    }

    return permutations.Select(p => string.Join(delimiter, p));
} 

您可以使用的一种算法基本上就像计算一样:

  • 从每个列表中的第0项开始(00000)
  • 增加最后一个值(00001,00002等)
  • 当你不能增加一个值时,重新设置它并增加下一个值(00009,00010,00011等)
  • 当你无法增加任何价值时,就完成了。
  • 功能:

    static IEnumerable<string> Permutations(
        string input,
        char separator1, char separator2,
        string delimiter)
    {
        var enumerators = input.Split(separator1)
            .Select(s => s.Split(separator2).GetEnumerator()).ToArray();
        if (!enumerators.All(e => e.MoveNext())) yield break;
    
        while (true)
        {
            yield return String.Join(delimiter, enumerators.Select(e => e.Current));
            if (enumerators.Reverse().All(e => {
                    bool finished = !e.MoveNext();
                    if (finished)
                    {
                        e.Reset();
                        e.MoveNext();
                    }
                    return finished;
                }))
                yield break;
        }
    }
    

    用法:

    foreach (var perm in Permutations("a|b,c,d|e|f|g,h|i", '|', ',', "/"))
    {
        Console.WriteLine(perm);
    }
    
    链接地址: http://www.djcxy.com/p/11805.html

    上一篇: Split and join multiple logical "branches" of string data

    下一篇: open failed:ENOENT (No such file or directory) error