tags:

views:

89

answers:

3

Does a smarter way than the following exist to resize a rectangular array?

double[,] temp = new double[newSize, originalSecondDimension];
Array.Copy(original, temp, original.Length);

I was concerned about duplicating a huge array and the memory necessary to do it. What does the Array.Resize() do internally?

Thanks,

Alberto

+3  A: 

You should defer performance micro-optimizations until a point where you actually measure and observe a problem. That said...

Resizing arrays in .NET requires them to be reallocated. Memory in a .NET process is (generally) laid out without gaps - so you cannot resize something like an array without moving it to a new location in the heap.

You normally should not care about how Resize() works internally - but in this case, the documentation actually explicitly describes what happens:

This method allocates a new array with the specified size, copies elements from the old array to the new one, and then replaces the old array with the new one.

Keep in mind that memory allocation in .NET is quite efficient - it mostly involves moving a high-water mark pointer up the address space of the heap and zeroing out the memory. Unless you are allocating an unusually large array, or doing so over and over in a tight loop you are not likely to run into issues.

There's really no better way to resize multi-dimensional data, in your case. However - you should strongly consider encapsulating this behavior in a custom class. It's not a good idea to pass around raw array objects - there are too many ways for things to go wrong. Especially, since when resized there is a new array instance - which could break any code that holds on to references to the old array instance and assumes they are still valid.

You can always create a class that provides indexer properties and has the syntactic "look-and-feel" of a multidimensional array, without actually exposing one. Unfortunately, to my knowledge there are no built-in multi-dimensional collection classes in the .NET class library. However, writing a simple wrapper should not be too hard.

By the way, if you are truly concerned about performance, you should be aware that .NET multdimensional arrays are know to perform significalty slower than one dimensional and even jagged arrays (double[][]).

LBushkin
One thing to mention though ... no there is no better way for multi-dimensional data.
Obalix
You can have a collection of collections
Joel Coehoorn
@Joel Coehoorn: Sure, *but I would still write a wrapper class to control the semantics that are desired*. For example, it may be a problem if one collection could be resized to be larger than the others (as in a jagged array or collection of collections). Only the OP knows what he needs - but it's never a bad idea to encapsulate the behavior you want - as opposed to spreading the knowledge and rules throughout multiple places in the code.
LBushkin
@LBushkin: How can you say that jagged arrays are faster than rectangualr ones? It seems impossible by design to me... Do you consider creating, filling and accessing them?
devdept
@devdept - Don't take my word on it. Write some test code and look at the emmitted IL, then profile it for reads, writes, and resizes. Or read this article - it discusses the performance characteristics of .NET arrays: http://www.codeproject.com/KB/dotnet/arrays.aspx
LBushkin
+2  A: 

Yes, there is a smarter way: Don't use an array! If you find yourself with an array that you need to re-size, you should be using a collection type instead.

Joel Coehoorn
Depends. If implementing a mathematical model (where the algorithms are defined using vectors, matrixes, hypercubes, etc), .NET arrays can be the best/most efficient way to store the data. Even if they require a wrapper class written around them for ease of use.
CuppM
+1  A: 

My guess is that you can't. Array.Resize() takes a ref T[], suggesting that it works something like this:

int[] a = new int[1];
int[] b = a;
Array.Resize(b,2);
Debug.Assert(a.Length == 1);
Debug.Assert(b.Length == 2);

If arrays could change size, then in concurrent code, you couldn't optimize away bounds checks, and you'd have to do something for each access to stop it from changing size under your feet:

for (int i = 0; i < a.Length; i++) { sum += a[i]; }

There might be an exception: It's theoretically possible to increase the size of the array provided the array doesn't have to be reallocated (memory alignment probably means resizing byte[1] to byte[4] in-place should generally be possible). It's far more common that the array will be reallocated, though, so there's little point in worrying about this.

tc.
The documentation for `Resize()` clearly states how it works: `This method allocates a new array with the specified size, copies elements from the old array to the new one, and then replaces the old array with the new one.`
LBushkin