我有一个多维数组,我想以简单快速的方式初始化:
double[,,] arr = new double[4,5,6];
// doesn't work by design
foreach(double d in arr)
d = ... ; // my initialization value
这显然不起作用。但是我希望有一个通用函数来将所有数组值设置为选择的默认值。使用自己的类,我可以编写一个特殊的构造函数,但是对于值类型我没有真正的想法。使用C ++,我可以使用一个for循环以线性方式访问所有项目,但在C#中我认为我将使用尽可能多的循环,因为我有维度。我目前还没有更好的解决方案(或者我使用的是不安全的代码和指针算法,这可能会有效。)。
这样做有更优雅的方式吗?
答案 0 :(得分:3)
不太确定它是否是您想要的,但是以下扩展方法将允许您初始化数组中的每个值,而不管维度的数量。
public static class ArrayExtensions
{
public static void Set<T>(this Array array, T defaultValue)
{
int[] indicies = new int[array.Rank];
SetDimension<T>(array, indicies, 0, defaultValue);
}
private static void SetDimension<T>(Array array, int[] indicies, int dimension, T defaultValue)
{
for (int i = 0; i <= array.GetUpperBound(dimension); i++)
{
indicies[dimension] = i;
if (dimension < array.Rank - 1)
SetDimension<T>(array, indicies, dimension + 1, defaultValue);
else
array.SetValue(defaultValue, indicies);
}
}
}
像这样使用:
int[, ,] test1 = new int[3, 4, 5];
test1.Set(1);
int[,] test2 = new int[3, 4];
test2.Set(1);
int[] test3 = new int[3];
test3.Set(1);
答案 1 :(得分:2)
我强烈建议使用1D数组,并按顺序映射值。您需要将indeces i
,j
,k
,...
转换为正确的数组索引,该索引使用下面的Que()
函数完成,部分通用数组类SeqArray<T>
。
// Test code first
class Program
{
static void Main(string[] args)
{
/* 3 pages, of a 4x2 matrix
*
* |16 17|
* | 8 9|19|
* | 0 1|11|21|
* | 2 3|13|23|
* | 4 5|15|
* | 6 7|
*
* shown above are the sequential indeces for a rank 3 array
*/
SeqArray<double> arr = new SeqArray<double>(3, 4, 2);
// Initialize values to squential index "num"
int num = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
for (int k = 0; k < 2; k++)
{
arr[i, j, k] = num++;
}
}
}
// Check that the array values correspond to the index sequence
num = 0;
for (int i = 0; i < 3 * 4 * 2; i++)
{
Trace.Assert(arr.InnerArray[i] == num++);
}
// Initialize with value=π
arr = new SeqArray<double>(Math.PI, 4, 5, 6);
}
}
public class SeqArray<T>
{
T[] values;
int[] lengths;
public SeqArray(params int[] lengths)
{
this.lengths = lengths;
int N = 1;
for (int i = 0; i < lengths.Length; i++)
{
N *= lengths[i];
}
values = new T[N];
}
public SeqArray(T value, params int[] lengths) : this(lengths)
{
for (int i = 0; i < values.Length; i++)
{
values[i] = value;
}
}
public int[] Lengths { get { return lengths; } }
public int Size { get { return values.Length; } }
internal T[] InnerArray { get { return values; } }
public int Que(params int[] indeces)
{
// Check if indeces are omited like arr[4] instead of arr[4,0,0]
if (indeces.Length < lengths.Length)
{
// Make a new index array padded with zeros
int[] temp = new int[lengths.Length];
indeces.CopyTo(temp, 0);
indeces = temp;
}
// Count the elements for indeces
int k = 0;
for (int i = 0; i < indeces.Length; i++)
{
k = lengths[i] * k + indeces[i];
}
return k;
}
public T this[params int[] indeces]
{
get { return values[Que(indeces)]; }
set { values[Que(indeces)] = value; }
}
}
答案 2 :(得分:1)
以下是Andy Holt发布的非递归版本替代版本:
public static void SetAll<T>(this Array array, T value)
{
var sizes = new int[array.Rank];
sizes[array.Rank - 1] = 1;
for (var d = array.Rank - 2; d >= 0; d--)
{
sizes[d] = array.GetLength(d + 1)*sizes[d + 1];
}
for (var i = 0; i < array.Length; i++)
{
var remainder = i;
var index = new int[array.Rank];
for (var d = 0; d < array.Rank && remainder > 0; d++)
{
index[d] = remainder / sizes[d];
remainder -= index[d]*sizes[d];
}
array.SetValue(value, index);
}
}