Multidimensional array, elements accessed by vector

.net, arrays, c#, multidimensional-array

Solution

Although there are no off-the-shelf collections like that, you can easily emulate them using a `Dictionary<int[],double>` and a custom `IEqualityComparerer<int[]>`, like this:

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);
    }
}

With this equality comparer in hand, you can do this:

// 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

If you need to have a certain capacity and a specific number of dimensions, you can modify the `ArrayEq` to be more strict at validating the data.

If you knew the number of dimensions at compile-time, you could use one of the `Tuple<...>` classes instead of arrays for potentially better performance. You could also define extension methods on multi-dimensional, say, `double[,,,]`, arrays, to take vectors of indexes. Neither of these two approaches offers the same flexibility, though (which is a common trade-off -- better performance can often be gained by reducing flexibility).

EDIT: If you need to pre-allocate the storage and avoid storing your indexes, you could implement a multi-dimensional array yourself - like this:

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; }
    }
}

This is a straightforward implementation of row-major indexing scheme that uses generics.

Problem

Is there any multidimensional array/collection/whatever datatype in .Net, elements of which can be accessed by vector (to vary number of dimensions easily)? Like this (C#): ``` var array = new Smth<double>(capacity: new int[] {xCap, yCap, zCap}); array[new int[] {x, y, z}] = 10.0; ``` To clarify: there is no need to explain how can I write such datatype manually. Upodate: I mean varying before creation, not after. ``` // 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; ```

Original source