How to set values ββin multidimensional array using linear index
What is the most efficient way to set values ββin multidimensional C # arrays using a linear index? For example, given array ...
int[,,] arr2 = { {{0,1,2}, {3,4,5}, {6,7,8}}
, {{9,10,11}, {12,13,14}, {15,16,17}}
, {{18,19,20}, {21,22,23}, {24,25,26}}
};
How to set all elements to 30 using linear index ...
//This code does not work
for (int i = 0; i < arr.Length; i++)
{
arr.SetValue(30, i);
}
Obviously the SetValue () above doesn't work with multidimensional arrays.
Here is the best solution I could think of ...
EDIT: Added some clarification to the code ...
static class Program
{
static void Main(string[] args)
{
//Sample input.
int[,,] arr2 = { {{0,1,2}, {3,4,5}, {6,7,8}}
, {{9,10,11}, {12,13,14}, {15,16,17}}
, {{18,19,20}, {21,22,23}, {24,25,26}}
};
int[] arr1 = { 1, 2, 3, 4 };
setElementsTo30(arr2);
setElementsTo30(arr1);
}
//Must be able to process int arrays of arbitrary dimensions and content
private static void setElementsTo30(Array arr)
{
IList<int> cumulativeLength = getCumulativeLengths(arr);
for (int i = 0; i < arr.Length; i++)
{
SetValue(arr, i, 30, cumulativeLength);
}
}
public static void SetValue(this Array arr, int index, object value, IList<int> cumulativeLength)
{
int[] arrayIndex = new int[arr.Rank];
for (int dim = arr.Rank-1; dim >= 0; dim--)
{
arrayIndex[dim] = index / cumulativeLength[dim] % arr.GetLength(dim);
}
arr.SetValue(value, arrayIndex);
}
private static IList<int> getCumulativeLengths(Array arr)
{
List<int> lengths = new List<int>(arr.Rank);
for (int dim = 0; dim < arr.Rank; dim++)
{
int prod = 1;
for (int i = dim + 1; i < arr.Rank; i++)
{
prod *= arr.GetLength(i);
}
lengths.Add(prod);
}
return (IList<int>)lengths;
}
}
Is there a way to do the same more efficiently and perhaps use something provided by the framework itself (i.e. something that can be used without too much hassle.)
Thank you
SDX2000.
source to share
why do you need IList?
static void SetValue2(this Array a, object value, int i) {
int[] indices = new int[a.Rank];
for (int d = a.Rank - 1; d >= 0; d--) {
var l = a.GetLength(d);
indices[d] = i % l;
i /= l
}
a.SetValue(value, indices);
}
Test code:
static void Main(string[] args) {
int[, ,] arr2 = {
{{0,1,2}, {3,4,5}, {6,7,8}},
{{9,10,11}, {12,13,14}, {15,16,17}},
{{18,19,20}, {21,22,23}, {24,25,26}}
};
for (int i = 0; i < arr2.Length; i++) {
arr2.SetValue2(30, i);
}
}
source to share
Do you know how many tuples will initially exist? If you say a matrix with dimensions axbxcxd, could you please use the following to get a list of all indices:
for i=0 to (a*b*c*d)
Array[i % a, (i/a) % b, (i/(a*b) % c, i / (a*b*c)] = 30
So, when the counter rolls over different bounds, each successive index is incremented. If there are more, this generalization to n-tuple simply multiplies the previous values. One could change the index arithmetic if one wanted to go down a different path.
source to share
SetValue()
must work. Check out this one for a little more inspiration.
EDIT: Could you just do
{{30,30,30}, {30,30,30}, {30,30,30}} , {{30,30,30}, {30,30,30}, {30,30,30}} , {{30,30,30}, {30,30,30}, {30,30,30} }
As a side note, are you sure you want to return IList<int>
from getCumulativeLengths
?
I have always thought to be generous in entering and strict in leaving.
source to share
public static void CopyToMultidimensionalArray(this IList<object> source, Array target, IList<int> dimensions)
{
var indices = new int[dimensions.Count];
for (var i = 0; i < source.Count; i++)
{
var t = i;
for (var j = indices.Length - 1; j >= 0; j--)
{
indices[j] = t % dimensions[j];
t /= dimensions[j];
}
target.SetValue(source[i], indices);
}
}
source to share