多维数组,通过向量访问元素

4
在 .Net 中是否有任何多维数组/集合/任何数据类型,可以通过向量访问其元素(以便轻松地改变维数)? 就像这样(C#):
var array = new Smth<double>(capacity: new int[] {xCap, yCap, zCap});
array[new int[] {x, y, z}] = 10.0;

澄清一下:无需解释如何手动编写此类数据类型。

更新:

我的意思是在创建之前进行变化,而不是之后。

// 3D array
var array = new Smth<double>(capacity: new int[] {xCap, yCap, zCap});
array[new int[] {x, y, z}] = 10.0;

// 6D array
var array = new Smth<double>(capacity: new int[] {xCap, yCap, zCap, tCap, vCap, mCap}); 
array[new int[] {x, y, z, t, v, m}] = 10.0;

你知道编译时的维度数量吗?我猜答案是否定的,对吧? - Sergey Kalinichenko
你知道在查找时维度的数量吗?你能提供一些不同维度的例子吗? - Bobson
1个回答

6
虽然没有现成的集合与其相匹配,但您可以使用Dictionary<int[], double>和自定义的IEqualityComparerer<int[]>来轻松模拟它们,如下所示:
class ArrayEq : IEqualityComparerer<int[]> {
    public bool Equals(int[] a, int[] b) {
        return a.SequenceEquals(b);
    }
    public int GetHashCode(int[] a) {
        return a.Aggregate(0, (p, v) => 31*p + v);
    }
}

有了这个相等比较器,您可以这样做:
// The number of dimensions does not matter: if you pass a different number
// of dimensions, nothing bad is going to happen.
IDictionary<int[],double> array = new Dictionary<int[],double>(new ArrayEq());
array[new[] {1,2,3}] = 4.567;
array[new[] {1,2,-3}] = 7.654; // Negative indexes are OK
double x = array[new[] {1,2,3}]; // Get 4.567 back

如果您需要具有特定容量和特定维数,可以修改ArrayEq以更严格地验证数据。
如果在编译时知道维数,则可以使用Tuple<...>类之一代替数组,以实现更好的性能。您还可以在多维数组上定义扩展方法,例如double[,,,],以获取索引向量。但是这两种方法都不提供相同的灵活性(这是一个常见的权衡 - 通过减少灵活性通常可以获得更好的性能)。 编辑:如果您需要预先分配存储空间并避免存储索引,则可以自己实现多维数组 - 就像这样:
class MultiD<T> {
    private readonly T[] data;
    private readonly int[] mul;
    public MultiD(int[] dim) {
        // Add some validation here:
        // - Make sure dim has at least one dimension
        // - Make sure that all dim's elements are positive
        var size = dim.Aggregate(1, (p, v) => p * v);
        data = new T[size];
        mul = new int[dim.Length];
        mul[0] = 1;
        for (int i = 1; i < mul.Length; i++) {
            mul[i] = mul[i - 1] * dim[i - 1];
        }
    }
    private int GetIndex(IEnumerable<int> ind) {
        return ind.Zip(mul, (a, b) => a*b).Sum();
    }
    public T this[int[] index] {
        get { return data[GetIndex(index)]; }
        set { data[GetIndex(index)] = value; }
    }
}

这是一个使用泛型的行主索引方案的简单实现。

哎?如果你不想把它们存储,为什么一开始要使用它们呢? - Bobson
@dasblinkenlight 我的意思是,您使用了带有指定IEqualityComparererDictionary。但也许有类似于IEqualityComparerer的东西可以传递给List,以便它自己将int[]转换为int,就像在您的GetHashCode中一样? - Andriy Kashchynets
@andriy.kashchynets - 为什么不直接使用List<double>来存储您的数据?然后您可以使用array[0]array[1]等来获取它?或者只需使用Dictionary<int, double>,其中您有一个函数int ConvertKey(params int[]),该函数提供一个数字作为键?如果将int[]转换为int,那就是您实际上正在做的事情。我真的不明白您在寻找什么。 - Bobson
@Bobson 我想使用 List<double>。我不想像 array[ConvertIntArrayToInt(intArray)] 那样使用它,而是想使用 array[intArray] - 这就是我的问题所在。 - Andriy Kashchynets
@dasblinkenlight 是的,这就是我需要的。我非常感谢你的帮助,但是(正如我在问题中所写),没有必要编写实现。我可以自己做到。我只是询问标准的.Net工具 - 只是为了避免重新发明轮子。无论如何,非常感谢你,现在我可以直接复制粘贴。 - Andriy Kashchynets
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接