2

私の仕事は、配列のすべての可能なインデックスの組み合わせを生成することです。配列は、要素数が異なる単一、2D、3D、4D ... nD 配列である可能性があります。今のところ、ネストされた for ループを使用する単一、2D、および 3D 配列のみをサポートできます。

例:

byte[,,] sampleArray = new byte[5,4,3];

Generated Index Combinations:
sampleArray[0,0,0]
sampleArray[0,0,1]
sampleArray[0,0,2]
sampleArray[0,1,0]
sampleArray[0,1,1]
sampleArray[0,1,2]
sampleArray[0,2,0]
sampleArray[0,2,1]
sampleArray[0,2,2]
sampleArray[0,3,0]
sampleArray[0,3,1]
sampleArray[0,3,2]
sampleArray[1,0,0]
sampleArray[1,0,1]
sampleArray[1,0,2]
sampleArray[1,1,0]
sampleArray[1,1,1]
sampleArray[1,1,2]
sampleArray[1,2,0]
sampleArray[1,2,1]
sampleArray[1,2,2]
sampleArray[1,3,0]
sampleArray[1,3,1]
sampleArray[1,3,2]
sampleArray[2,0,0]
sampleArray[2,0,1]
sampleArray[2,0,2]
sampleArray[2,1,0]
sampleArray[2,1,1]
sampleArray[2,1,2]
sampleArray[2,2,0]
sampleArray[2,2,1]
sampleArray[2,2,2]
sampleArray[2,3,0]
sampleArray[2,3,1]
sampleArray[2,3,2]
sampleArray[3,0,0]
sampleArray[3,0,1]
sampleArray[3,0,2]
sampleArray[3,1,0]
sampleArray[3,1,1]
sampleArray[3,1,2]
sampleArray[3,2,0]
sampleArray[3,2,1]
sampleArray[3,2,2]
sampleArray[3,3,0]
sampleArray[3,3,1]
sampleArray[3,3,2]
sampleArray[4,0,0]
sampleArray[4,0,1]
sampleArray[4,0,2]
sampleArray[4,1,0]
sampleArray[4,1,1]
sampleArray[4,1,2]
sampleArray[4,2,0]
sampleArray[4,2,1]
sampleArray[4,2,2]
sampleArray[4,3,0]
sampleArray[4,3,1]
sampleArray[4,3,2]

私のコード:

     protected void GenerateIndexCombinations(int indexCounter, 
     ref List<List<int>> indexList, Array arr, ref List<int> index)
        {
            int dimSize1 = arr.GetLength(0);
            int dimSize2 = 0;
            int dimSize3 = 0;
            if (indexCounter > 1)
            {
                dimSize2 = arr.GetLength(1);
                if (indexCounter > 2)
                {
                    dimSize3 = arr.GetLength(2);
                }
            }

            for (int a = 0; a < dimSize1; a++)
            {
                if (dimSize2 > 0)
                {
                    for (int b = 0; b < dimSize2; b++)
                    {
                        if (dimSize3 > 0)
                        {
                            for (int c = 0; c < dimSize3; c++)
                            {
                                index = new List<int>();
                                index.Add(a);
                                index.Add(b);
                                index.Add(c);
                                indexList.Add(index);
                            }
                        }
                        else
                        {
                            index = new List<int>();
                            index.Add(a);
                            index.Add(b);
                            indexList.Add(index);
                        }
                    }
                }
                else
                {
                    index = new List<int>();
                    index.Add(a);
                    indexList.Add(index);
                }
            }
        }

ここで:
int indexCounter は次元数です。
配列 arr は、リフレクションを使用してアクセスされる配列です。

Array arr = fieldInfoArray[j].GetValue(_classInstance) as Array;


ref List<List<int>> indexList組み合わせのコンテナになります。
ref List<int> indexindexListに追加された個体番号です。

次元のサイズと次元ごとの要素数が固定されていないため、組み合わせを動的に生成して、ネストされた for ループを置き換えたいのですが、それを行う方法はありますか?

回答ありがとうございます。

4

1 に答える 1

3

Eric Lippert は、まさにこの問題についてブログに書いています。あなたの特定のケースではEnumerable.Range(0, 5)、 、Enumerable.Range(0, 4)、およびのデカルト積を探していますEnumerable.Range(0, 3)。一般に、次のようなものが必要です。

var dimensions = 
     Enumerable.Range(0, array.Rank)
               .Select(r => Enumerable.Range(0, array.GetLength(r)));

次に、 で Eric のメソッドを呼び出しdimensionsます。ここでは、 を使用Array.Rankして行列の次元を取得し、 を使用Array.GetLengthして各次元に沿って長さを取得し、デカルト積を計算するために必要なシーケンスを動的に生成しています。したがって、各次元について、その次元をその次元に沿った一連の有効なインデックスに射影しますarray。したがって、

T[,,...,] array = new T[a_1, a_2, ..., a_n];

dimensionsシーケンスを等しくすることになります

(Enumerable.Range(0, a_1),
 Enumerable.Range(0, a_2),
 .
 .
 .,
 Enumerable.Range(0, a_n)
)

using System.Linq;
using System.Collections.Generic;
using System;

static class EnumerableExtensions {
    // credit: Eric Lippert
    public 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 })
        );
    }
}

class Program {
    public static void Main(string[] args) {
        int[,,] array = new int[5, 4, 3];
        var dimensions = 
            Enumerable.Range(0, array.Rank)
                      .Select(r => Enumerable.Range(0, array.GetLength(r)));
        var indexes = dimensions.CartesianProduct();
        foreach(var index in indexes) {
            Console.WriteLine(String.Join(",", index));
        }
    }
}
于 2013-06-23T02:14:31.113 に答える