我有一个多维矩阵,可以有任意数量的维度大于1。寻找一种可以访问矩阵中每个点的有效算法。
有关代码的一些信息: 矩阵具有值访问器(尽管这些并不是真正相关的)。
object value = matrixInstance.GetValue(int[] point);
matrixInstance.SetValue(object value, int[] point);
注意:参数 point 是索引数组,必须与维度匹配或抛出异常。
有关矩阵结构的信息可以通过以下方式获得:
int numDims = matrixInstance.Rank; //# dimensions
int sizeDim = matrix.getRankSize(int index); // length of specified dimension
我想使用相对有效的算法迭代矩阵的所有可能点。
例如,在2x3 2D矩阵中,将访问以下六个点:
[0,0]
[0,1]
[0,2]
[1,0]
[1,1]
[1,2]
算法必须达到N维:2,3,4等。为了提高效率,我最终会使用C# iterator来返回积分。
答案 0 :(得分:4)
您可以在树上查看一个树,该树的所有值都在树叶处:
是矩阵
[0,0] = 'A'
[0,1] = 'B'
[1,0] = 'C'
[1,1] = 'D'
只需应用任何众所周知的树遍历解决方案。
这是一个递归解决方案(未经测试):
IEnumerable<Point> GetPoints(Matrix matrix, int[] indexes)
{
if (indexes.Length == matrix.Rank)
{
yield return matrix.GetValue(indexes);
}
else
{
for (int i = 0; i < matrix.GetRankSize(indexes.Length); i++)
{
foreach (var point in
GetPoints(matrix, indexes.Concat(new int[] { i }).ToArray())
{
yield return point;
}
}
}
}
将此转换为使用显式堆栈的迭代版本应该是相当简单的。
答案 1 :(得分:1)
如果您可以在运行时为每个维度生成索引值的集合,则可以使用Eric Lippert's LINQ snippet生成索引值的所有组合。
Eric制作所有组合集合的方法:
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}));
}
所以,对于你的2x3例子,
int [ , ] dimensions= { { 0, 1}, { 0, 1, 2 } } ;
var allMatrixCells = CartesianProduct<int>(dimensions);
foreach(var cellLocation in allMatrixCells )
{
...
}
答案 2 :(得分:1)
只需递归迭代每个维度。例如,第一次调用迭代第一个维度的每个值,调用自身迭代第二个维度的每个值,依此类推,无论你有多少维度。然后,基本情况(当没有更多维度时)是返回相关单元格中的值,而不是再次递归。
答案 3 :(得分:0)
您可以使用混合基数表示,请参阅例如http://en.wikipedia.org/wiki/Mixed_radix
例如,如果您有4个长度为4,3,2,7的维度,然后对应于索引a,b,c,d我们有数字a + 4 *(b + 3 *(c + 2 *) d))。从中恢复指数 数字n就像得到十进制数字一样,除了基数不同,即 a = n%4; n / = 4; b = n%3; n / = 3; c = n%2; N / = 2; d = n。
所以你会有一个for循环(在这种情况下为n = 0..4 * 3 * 2 * 7-1),其中索引可以 从上面的n中恢复。
然而,也许所有这些划分和模数都意味着这不是那么有效。