views:

101

answers:

5

Question very simple - say, i got function, which receives array as its arguments

void calc(double[] data)

how do "split" this data in two subarrays and pass to sub functions like this

calc_sub(data(0, length/2));
cals_sub(data(length /2, length /2));

i hope, you got the idea - in c++ i would write this

void calc(double * data, int len)
{
   calc_sub(data, len / 2); //this one modifies data!!
   calc_sub(data + len / 2, len / 2); //this one modifies data too!!
}

How to do same in C# without unecesary memory copying? I would need 2 memory copies here. 1) from data to splitted data 2) calc_sub 3) from splitted data back to data! This is huge waste of time and memory!

+4  A: 

The short answer is that to get a subarray, you'd have to create a new array and copy elements... Or if you were using c++, you'd be memcpying.

Now, why not just take the offset/count approach? When calling calc_sub(blargh[] array), instead use calc_sub(blargh[] array, int offset, int count)?

This is basically the c# way of passing a pointer to the start/half-pos element and telling the function to work on only half the array's elements.


I should note that unless you're working with huge double arrays, you really shouldn't be worrying about this. 64 bits = 8 bytes. Even if you had an array of 1000 elements, that's 8000 bytes, ~8 kB of memory, which you will pretty much free in less than a second...

Now, it's always a good idea to conserve memory where possible, but I'd rule this as premature optimization.

I should also note that arrays are passed by reference, as they are really objects, as opposed to ints or strings, so this method is the best memory-wise [it doesn't copy the array; it gives something like a pointer to the array object], but it's limited in that modifying the array in your function will modify the array passed outside of your function call.

ItzWarty
tons of code using "that" approach. Copy works allways, but aint there any "smarter" solution?
0xDEAD BEEF
I would not ask this, if performance wouldnt be an issue.
0xDEAD BEEF
+5  A: 

The easiest is probably using LINQs Take and Skip extension methods:

int half = data.Length / 2;
double[] sub1 = data.Take(half).ToArray();
double[] sub2 = data.Skip(half).ToArray();
Darin Dimitrov
Easy to read solution but I'm pretty sure it's rather slow since both tak,skip and ToArray probably results in a simple iteration of the collection resulting in two full iterations of the original data. If the size of the original data is low or time is not an issue it's a nice readable solution
Rune FS
Is it fast? CLR knows, how to optimize this stuff?
0xDEAD BEEF
I always try to write readable code and later perform load testing to verify if performance wasn't hurt. If this is the case then refactor.
Darin Dimitrov
To clarify about the performance: `Take` and `Skip` create a new enumerator from the original collection. So until you call `ToArray` nothing happens. Once you call `ToArray` half of the original array is iterated in order to create a new array, so both operations basically cost you a full iteration over the original array plus the memory it takes to store the new sub-arrays.
Darin Dimitrov
+2  A: 

Depending on what calc_sub does, you can make a IEnumerable class which takes the array and iterates over some part of the array. Something like ArraySegment, but better.

Sjoerd
+1  A: 

Go ahead and write your own subarray function like this:

public static class ArrayExtensions
{
  T[] SubArray<T>(this T[] arr, int startIndex,int count)
  {
    var sub = new T[count];
    Array.Copy(arr,startIndex,sub,o,count);
    return sub;
  }
}

and then you can use it like:

void calc(double[] data)
{
  var half = data.Length /2;
  data.SubArray(0, half ));
  data.SubArray(half , half ));
}
Rune FS
Already in my `public static class Extentions`... A must have in my opinion.
ItzWarty
The idea is, that calc_sub not only operates with data, but also return data!!!
0xDEAD BEEF
@0xDEAD BEEF, But calc sub returns a value calculated by the passed array, right? We honestly don't know what calc_sub does, so it's not really possible for us to give advice 100% targeted to you; we're guessing on what your situation is.
ItzWarty
@0xDEAD BEEF and what's the issue with splitting the array and then iterating to do the calculation? or would you preferre to do have a transformation operation instead?
Rune FS
A: 

If you can make the calc_sub method take an IEnumerable<double> instead of a double[], you can use extension methods to create expressions that return part of the array:

void calc(double[] data) {
  int half = data.Length / 2;
  calc_sub(data.Take((half));
  calc_sub(data.Skip(half));
}

This way you don't have to copy the data to new arrays, the expressions will return items from the original array.

Guffa
Is it fast? Calling IEnumberable.value instead of direct array access??
0xDEAD BEEF
it's reasonably fast but not as fast as direct access but do you know you have a performance problem?
Rune FS