Search code examples
c#functional-programming

How to create a multi-dimensional ImmutableArray?


It appears the MS documentation on ImmutableArray only refers to one-dimension array. It seems I may be able to wrap an entire array in ImmutableArray, then retrieve the entire array first (at index 0), then get the specific value at say [i, j].

ImmutableArray<T[,]> arr = ImmutableArray.Create<TVal[,]>(oneDimArray);
T value = arr[0][i, j];

Multidimensional arrays seem like a common need to me, and there must be a better way. Thanks for the help!


Solution

  • I agree with the comments made by jmcilhinney that multidimensional arrays are rarely needed, but perhaps that's just my limited experience after decades as a back-end and enterprise developer. Perhaps there are other areas (game development?) where they are more needed...

    That said, you can often use jagged arrays instead multidimensional arrays. This is also possible with ImmutableArray<T>, although not necessarily particularly easy to work with.

    As an example, here's how to initialise a n×m immutable jagged array with a default value:

    public static ImmutableArray<ImmutableArray<T>> Initialize<T>(int n, int m, T initialValue)
    {
        var inner = Enumerable.Range(1, m).Select(_ => initialValue).ToImmutableArray();
        return Enumerable.Range(1, n).Select(_ => inner).ToImmutableArray();
    }
    

    Here's an example of how to initialise a 2×3 array with the default value "foo":

    var arr1 = Jagged.Initialize(2, 3, "foo");
    

    'Changing' values inside of it is awkward at best:

    // Change value at (0, 1)
    var arr2 = arr1.Select(
        (a, i) => a.Select(
            (s, j) => i == 0 && j == 1 ? "bar" : s).ToImmutableArray()).ToImmutableArray();
    

    Depending on what you need it for, however, you can write helper methods to make such projections easier.

    Since the jagged array is immutable, the above expression doesn't change the original array arr1, but rather returns a new jagged array arr2.

    Data retrieval, on the other hand, is easy:

    // Retrieve value at (0, 1)
    string bar = arr2[0][1];
    

    As expected, bar has the value "bar".

    I often work with immutable data structures in C#, but usually I stick with IEnumerable<T>. You may have noticed that the above projection makes heavy use of LINQ anyway, so unless you have massive amounts of data, it's not clear why you need something like ImmutableArray, jagged or not...