可能的组合

时间:2014-01-15 17:40:14

标签: c# .net arrays list

我有一系列名单

List<string>[] possibleLines;

每个List&lt;&gt;的数组也可以具有不同的大小。可以有不同数量的字符串。前例

  • List<string>[0] - 可以有字符串“first string”,“second string”
  • List<string>[1] - “第三个字符串”,“第四个字符串”,“第五个字符串”

我需要获得所有可能的组合,每个字符串必须来自不同的列表(数组大小可能不同)。例如

  • “first string”,“4th string”
  • “first string”,“Fifth string”
  • “second string”,“4th string”

等等。

3 个答案:

答案 0 :(得分:5)

你在这里做的是计算未知数量的集合的笛卡尔积。 Eric Lippert描述了如何在this blog post中编写这个问题的解决方案(我强烈建议你阅读以了解他是如何提出这个解决方案的。)

他最终得到的代码是:

static IEnumerable<IEnumerable<T>> CartesianProduct<T>(
    this IEnumerable<IEnumerable<T>> sequences) 
{ 
  IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() }; 
  return sequences.Aggregate( 
    emptyProduct, 
    (accumulator, sequence) => 
      from accseq in accumulator 
      from item in sequence 
      select accseq.Concat(new[] {item})); 
}

答案 1 :(得分:1)

我认为这是一个非常酷的数学问题,但我想想象实际的过程,所以我写了这个想要测试Servy(好吧,Eric Lippert)写的:

int length = 4;
var lists = new List<List<string>>();
var random = new Random(1234);

for(int i = 0; i < length; i++)
{        
    var inLength = random.Next(4, 8);
    var tempList = new List<string();
    for (int j = 0; j < inLength; j++_
    {
        tempList.Add(string.Format("{{String Coords: {0}, {1}}}", i, j));
    }
    lists.Add(tempList);
}

var cp= lists.CartesianProduct();
var output = RenderString(cp);

RenderString

private static string RenderString(IEnumerable<IEnumerable<string>> cp)
{
    var sb = new StringBuilder();

    foreach (var item in cp)
    {
        sb.AppendLine(item.Aggregate((a, b) => a + b));
    }
    return sb.ToString();
}

这会给你一个output看起来像

{String Coords: 0, 0}{String Coords: 1, 0}{String Coords: 2, 0}{String Coords: 3, 0}
{String Coords: 0, 0}{String Coords: 1, 0}{String Coords: 2, 0}{String Coords: 3, 1}
{String Coords: 0, 0}{String Coords: 1, 0}{String Coords: 2, 0}{String Coords: 3, 2}
{String Coords: 0, 0}{String Coords: 1, 0}{String Coords: 2, 0}{String Coords: 3, 3}
{String Coords: 0, 0}{String Coords: 1, 0}{String Coords: 2, 0}{String Coords: 3, 4}
{String Coords: 0, 0}{String Coords: 1, 0}{String Coords: 2, 1}{String Coords: 3, 0}
...
{String Coords: 0, 4}{String Coords: 1, 4}{String Coords: 2, 6}{String Coords: 3, 4}

如果您想要了解正在发生的事情,那就太酷了。

答案 2 :(得分:0)

这是一种程序性更强的方法,读起来很恐怖,但速度是埃里克·利珀特(Eric Lippert)建议的两倍。

static IReadOnlyList<IReadOnlyList<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
{
    var arrays = sequences.Select(s => s.ToArray()).ToArray();
    var numColumns = arrays.Length;

    if (numColumns == 0)
    {
        return new[]
        {
            Array.Empty<T>()
        };
    }

    var arrayLengths = arrays.Select(l => l.Length).ToArray();

    var arrayIndices = new int[numColumns];
    var numRows = arrayLengths.Aggregate((x, y) => x * y);

    var lastColumnIndex = numColumns - 1;

    var combinations = new IReadOnlyList<T>[numRows];

    for (var rowIndex = 0; rowIndex < numRows; rowIndex++)
    {
        var items = new T[numColumns];
        for (var columnIndex = 0; columnIndex < numColumns; columnIndex++)
        {
            items[columnIndex] = arrays[columnIndex][arrayIndices[columnIndex]];
        }
        combinations[rowIndex] = items;

        for (var i = lastColumnIndex; i >= 0; i--)
        {
            var updatedIndex = arrayIndices[i] = (arrayIndices[i] + 1) % arrayLengths[i];
            if (updatedIndex > 0)
            {
                break;
            }
        }
    }

    return combinations;
}