生成数据源[10]大于所需组合长度的组合[5]

时间:2017-05-23 14:03:16

标签: c# loops for-loop combinations

我需要能够从预定义的int []生成10个整数的所有可能组合,然后将这些可能的组合作为List返回。每个组合必须长度5

示例:

{1, 2, 3, 4, 5},
{2, 3, 4, 5, 6},
{3, 4, 5, 6, 7}, etc.

到目前为止,我有以下内容:

int[] cardFaces = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
List<int[]> combos = new List<int[]>();

// For every value in the cardFaces array, get the value and the index.

foreach (var item in cardFaces.Select((value, i) => new { i, value }))
  {
    int value = item.value;
    int index = item.i;    
    int value1 = 0;
    int value2 = 0;
    int value3 = 0;
    int value4 = 0;
    int value5 = 0;

    // Need some nested loop code here, which will create combinations
    // from the cardFaces[] with a length of 5.

    int[] combo = {value1, value2, value3, value4, value5};

    combos.Add(combo);

  }

它不应包含任何重复。我对此非常陌生,所以我正在努力研究如何解决循环以获得我需要的组合。

1 个答案:

答案 0 :(得分:1)

这是一个更通用的实现。它需要一个可供选择的项目列表和要选择的项目数(k)。在您的情况下,k = 5

它的工作方式如下:初始化k'指针'指向源列表的第一个k元素。这是第一个组合。在视觉上我们有:

source:  [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
pointers:  ^  ^  ^  ^  ^

要获得下一个组合,请递增最后一个指针:

source:  [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
pointers:  ^  ^  ^  ^     ^

如果该指针现在超过列表的末尾,那么我们转到前一个指针并递增它并将最后一个指针移动到它之后的一个指针。所以我们说现在的组合如下:

source:  [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
pointers:  ^  ^  ^  ^                  ^

如果我们递增最后一个指针,它将超过结束。所以我们从末尾看下一个指针并递增它并将我们的最后一个指针放在它之后:

source:  [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
pointers:  ^  ^  ^     ^  ^

然后我们像往常一样返回递增最后一个指针:

source:  [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
pointers:  ^  ^  ^     ^     ^

source:  [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
pointers:  ^  ^  ^     ^        ^

等等。每次最后一个指针到达结尾时,都会移动下一个指针。一旦它到达终点(实际上在它之前),你将 next 移回一个。基本上,一旦你的最后一个指针到达终点,你将向后移动指针列表,试图向前移动每个指针直到找到一个可以向前移动的指针。找到一个后,将所有指针设置为后面的序列。例如:

source:  [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
pointers:  ^                 ^  ^  ^   ^

我们会回过头来注意除了第一个之外我们不能移动它们。所以我们将那一个移动到下一个位置,然后将其他所有其他位置重置到它之后:

source:  [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
pointers:     ^  ^  ^  ^  ^

如果第一个指针的末尾小于k个元素,那么我们就是最后一个组合,我们可以停止。

在代码中,看起来像这样:

public static IEnumerable<IEnumerable<T>> GetOrderedPermutations<T>( IList<T> source, int k )
{
    if( k == 0 ) yield return Enumerable.Empty<T>();
    if( k == source.Count ) yield return source;
    if( k > source.Count ) yield break;
    var pointers = Enumerable.Range( 0, k ).ToArray();

    while( pointers[0] <= source.Count - k )
    {
        yield return pointers.Select( p => source[p] );

        pointers[k - 1]++;

        int i = k - 2;
        while( pointers[k - 1] >= source.Count && i >= 0 )
        {
            pointers[i]++;

            for( int j = i + 1; j < k; ++j )
            {
                pointers[j] = pointers[j - 1] + 1;
            }

            --i;
        }
    }
}