_
How do you work with multi-dimentional arrays? Any best practices you can share?
_
I ask this question because it is rather common dilemma among unity programmers and there is plenty of confusion around this topic. The whole issue starts when one day you write code like this…
[SerializeField] int[] arrayA;
[SerializeField] int[,] arrayB;
[SerializeField] int[][] arrayC;
…and you notice that arrayA will serialize fine, but arrayB and arrayC wont (wont show up in Inspector). So how you deal with that?
_
Tragicomical anecdote: UE4 has this problem as well. TArray<TArray<int32>> wont serialize nor show up in Details panel. Made me chuckle, won’t lie : )
_
My approach is to keep your data as basic and serializable 1-dimentional array, but create some kind of facade object that provides n-dimensional indexer accessors ( [ x , y , … ]) so the the index conversion issue disappears almost completely.
_
Implementation example: tiny facade struct that provides [x,y] indexer accessors for arrays · GitHub
_
I’ve thrown this together when ran into this problem. You almost can use it as an array and convert to it. Not so invisible as I hoped though. You can implicitly cast ArrayElement and T back and forth unless you want to cast array to ArrayElements, then you’re out of luck it seems, only an extension method can do that, no casting to array of type is available in C#.
//Example of use
int[][] zzz = new int[][] { new int[]{ 1, 2, 3 }, new int[]{ 4, 5, 6 } };
ArrayElement<int[]> xxx = zzz;
ArrayElement<int>[] ccc = zzz.ToArrayElemets();
Here’s the implementation:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace MultidimensionalArrayUtils {
[Serializable]
public class ArrayElement<T> : IEnumerable, IEnumerable<T> {
[SerializeField]
private T[] _array;
public T[] Array { get => _array; }
public T this[int i] => _array*;*
-
public IEnumerator GetEnumerator() => _array.GetEnumerator();*
-
IEnumerator<T> IEnumerable<T>.GetEnumerator() {*
-
foreach (var item in _array) {*
-
yield return item;*
-
}*
-
}*
-
public ArrayElement(T[] array) {*
-
_array = array;*
-
}*
-
public ArrayElement(IEnumerable<T> collection) {*
-
_array = collection.ToArray();*
-
}*
-
public static implicit operator T[](ArrayElement<T> arr) => arr == null ? new T[0] : arr.Array;*
-
public static implicit operator ArrayElement<T>(T[] arr) => new ArrayElement<T>(arr == null ? new T[0] : arr);*
-
}*
-
public static class ArrayElementExtensions {*
-
public static ArrayElement<T>[] ToArrayElemets<T>(this IEnumerable<IEnumerable<T>> collectionOfCollections) =>*
-
collectionOfCollections.Select(t => (ArrayElement<T>)t.ToArray()).ToArray();*
-
public static ArrayElement<T>[] ToArrayElemets<T>(this IEnumerable<T[]> collectionOfCollections) =>*
-
collectionOfCollections.Select(t => (ArrayElement<T>)t).ToArray();*
-
}*
}