【问题标题】:Generating combinations where the data source [10] is larger than the required combination length [5]生成数据源 [10] 大于所需组合长度 [5] 的组合
【发布时间】:2017-05-23 14:03:16
【问题描述】:

我需要能够从预定义的 int[] 生成 10 个整数的所有可能组合,然后将这些可能的组合作为列表返回。每个组合的长度必须为 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);

  }

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

【问题讨论】:

标签: c# loops for-loop combinations


【解决方案1】:

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

它的工作原理是这样的:初始化k'pointers' 指向源列表的第一个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;
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-02
    • 1970-01-01
    • 2017-07-10
    • 1970-01-01
    • 1970-01-01
    • 2019-05-16
    • 1970-01-01
    相关资源
    最近更新 更多