Reputation: 1356
How can I efficiently assign a common initial value to a large array? For instance if I have a 100 by 100 by 100 integer array where all initial values should be zero.
In matlab I would simply write:
array = zeros(100,100,100);
How can I do this without a loop in C#?
Upvotes: 2
Views: 585
Reputation: 14565
In the C programming land it is common to use OS functions like memcpy or CopyMemory to efficiently move memory from one place to another. That is far better than using loops because the operating system will use dedicated hardware (DMA) to perform the operation.
I'm not sure if this is useful for your simple case, but it is possible to import these functions from certain DLLs if you want.
[DllImport("kernel32.dll")]
static extern void CopyMemory(IntPtr destination, IntPtr source, uint length);
static void Main(string[] args)
{
byte[] a = new byte[10]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
byte[] b = new byte[10];
IntPtr pa = Marshal.UnsafeAddrOfPinnedArrayElement(a, 0);
IntPtr pb = Marshal.UnsafeAddrOfPinnedArrayElement(b, 0);
CopyMemory(pb, pa, 10);
}
The CopyMemory function will only work for contiguous memory blocks, so be aware on how you call it.
IMPORTANT EDIT:
If you look the commentaries below you will notice that the piece of code showed above is far from being "usable" because it can corrupt you application memory without you ever knowing about it. A better approach is to use the Buffer.BlockCopy method, as suggested by codesparkle, which probably does same thing internally but in a safe manner:
byte[] a = new byte[10]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
byte[] b = new byte[10];
Buffer.BlockCopy(a, 0, b, 0, 10);
Upvotes: -1
Reputation: 534
You can use Enumerable.Repeat
for that purpose like so:
int[] zeros1Dim = Enumerable.Repeat(0, 100).ToArray();
int[][] zeros2Dim = Enumerable.Repeat(zeros1Dim, 100).ToArray();
int[][][] array = Enumerable.Repeat(zeros2Dim, 100).ToArray();
Upvotes: 1
Reputation: 2309
Just for the sake of argument (I do not personally think it would be a good programming style) but it can be done in C# in one line and technically without a loop but with LINQ
int[,,] cube = new int[A, B, C];
Enumerable.Range(0, A*B*C).Select(i => cube[i/(B*C), i%(B*C)/C, i%C] = 1).Count();
Count() here is only necessary to make the sequence to be enumerated, its result is ignored. This is to implement MATLAB's ones() function. To implement zeros() the following can be used:
Array.Clear(cube, 0, A*B*C);
Upvotes: 2
Reputation: 48596
I don't know of an idiomatic, non-loop way of initializing arrays in C#, and based on the answers here, it seems like neither do others. Unsafe memory copying could require fewer lines of code, though it really muddies the meaning of what you're doing: it emphasizes the mechanism (move this value to this memory address) over the semantics (make this entire multi-dimensional array equal to the same value.)
Given that, my suggestion would be to bite the bullet, use a loop, but then abstract it away in a pleasantly named method:
public static T[,,] FillArrayWithValue<T>(this T[,,] array, T value)
{
// Loops go here
}
Stick that in a static utility class somewhere, and then your callsite becomes:
int[,,] myArray = new int[4, 5, 6];
myArray.FillArrayWithValue(value);
Upvotes: 0
Reputation: 22245
public void SetAllValues(int[,,] data, int value) {
for (int x = 0; x < data.GetLength(0); x++) {
for (int y = 0; y < data.GetLength(1); y++) {
for (int z = 0; z < data.GetLength(2); z++) {
data[x, y, z] = value;
}
}
}
}
Upvotes: 1