4

代わりに再帰を使用するようにネストされた for ループを更新しようとすると、いくつかの問題が発生します。再帰を使用する場合、以前の for ループから a、b、および c 変数にアクセスすることは可能ですか? 以下は、再帰呼び出しに変換しようとしているものの簡単な例です。

for(int a= 0; a < 10; a++)
{
    for(int b = 0; b < 20; b++)
    {
        for(int c = 0; c < 10; c++)
        {
            int[] indexes = new int[3]{a,b,c}
            collection.add(indexes);
        }
    }
}

編集: ユーザーが必要なレベルの数を選択できるように、ソリューションは実行時に調整できる必要があります。

4

6 に答える 6

9

これは再帰的な解決策です(関数型プログラミングスタイルを使用):

public static IEnumerable<IEnumerable<int>> GetCombinations(IEnumerable<int> limits)
{
    if (limits.Any() == false)
    {
        // Base case.
        yield return Enumerable.Empty<int>();
    }
    else
    {
        int first = limits.First();
        IEnumerable<int> remaining = limits.Skip(1);
        IEnumerable<IEnumerable<int>> tails = GetCombinations(remaining);

        for (int i = 0; i < first; ++i)
            foreach (IEnumerable<int> tail in tails)
                yield return Yield(i).Concat(tail);
    }
}

// Per http://stackoverflow.com/q/1577822
public static IEnumerable<T> Yield<T>(T item)
{
    yield return item;
}

サンプル使用:

var sequences = GetCombinations(new [] { 5, 3, 2, 4 /* ... */ });
foreach (var sequence in sequences)
    Console.WriteLine(string.Join(", ", sequence));

/* Output:
0, 0, 0, 0
0, 0, 0, 1
0, 0, 0, 2
0, 0, 0, 3
0, 0, 1, 0
0, 0, 1, 1
0, 0, 1, 2
0, 0, 1, 3
0, 1, 0, 0
0, 1, 0, 1
0, 1, 0, 2
... */

OPの特定のシナリオ(配列をに追加するcollection)の場合:

var sequences = GetCombinations(new [] { 10, 20, 10 });
collection.AddRange(sequences.Select(s => s.ToArray()));
于 2013-09-20T10:45:26.197 に答える
4

わかりました、これで試してください

static void AddToCollectionRecursive(
    List<int[]> collection,
    params int[] counts)
{
    AddTo(collection, new List<int>(), counts, counts.Length - 1);
}

static void AddTo(
    List<int[]> collection,
    IEnumerable<int> value,
    IEnumerable<int> counts,
    int left)
{
    for (var i = 0; i < counts.First(); i++)
    {
        var list = value.ToList();

        list.Add(i);

        if (left == 0)
        {
            collection.Add(list.ToArray());
        }
        else
        {
            AddTo(collection, list, counts.Skip(1), left - 1);
        }
    }
}

使い方はこんな感じAddToCollectionRecursive(collection, 10, 20, 10);です。

于 2013-09-20T10:57:49.963 に答える
2

このようなものはうまくいきます:

public void CreateIndexes(int a, int b, int c, Collection collection)
{
    if(c == 10) {b++; c = 0;}
    if(b == 20) {a++; b = 0;}
    if(a == 10) return;

    int[] indexes = new int[3]{a,b,c}
    collection.add(indexes);
    c++;

    CreateIndexes(a, b, c, collection);
}
于 2013-09-20T10:34:39.897 に答える
1

再帰を使用してこの問題を解決すると、より多くのメモリやその他のリソースが消費されると思います。

しかし、私の提案があります:

private void FunctionName(int a, int b, int c, List<int[]> list)
{
    if (a<10)
    { 
       if (b<20)
       {
           if (c<10)
           {
               list.Add(new[] { a, b, c });
               c++;
               FunctionName(a,b,c,list);
            }
            else
            {
                 c=0;
                 b++;
                 FunctionName(a,b,c,list);
            }
       }
       else
       {
          b=0;
          a++;
          FunctionName(a,b,c,list);
       }
    }
 }

次のように呼び出します: FunctionName(0,0,0,list)。

それがうまくいくことを願っています!^^

于 2013-09-20T10:39:23.097 に答える
1

私の頭の上から、つまりテストされていないので、次のようなものがうまくいくかもしれません:

    List<int[]> collection = new List<int[]>();
    private void AddValues(int a, int b, int c)
    {

        collection.Add(new[] { a, b, c });

        if (c < 10)
        {
            c++;
            AddValues(a, b, c);
        }

        if (b < 20)
        {
            b++;
            c = 0;
            AddValues(a, b, c);   
        }

        if (a < 10)
        {
            a++;
            b = 0;
            c = 0;
            AddValues(a, b, c);
        }
    }

次のように呼び出して開始します。

AddValues(0, 0, 0);
于 2013-09-20T10:28:01.150 に答える