我的任务是生成数组的所有可能的索引组合,其中数组可能是具有不同数量元素的单个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> index
是添加到indexList的个别号码。
由于尺寸大小不固定,以及每个尺寸的元素数量,我想动态生成组合以替换我的嵌套for循环,有没有办法做到这一点?
感谢您的回答。
答案 0 :(得分:3)
Eric Lippert正好blogged关于这个问题。在您的具体情况下,您正在寻找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)));
然后在dimensions
上调用Eric的方法。在这里,我使用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));
}
}
}