C# Changing the number of dimensions in an array - c#

Is it possible, in C#, to convert a multi-dimensional array into a 1D array without having to copy all the elements from one to the other, something like:
int[,] x = new int[3,4];
int[] y = (int[])x;
This would allow the use of x as if it were a 12-element 1D array (and to return it from a function as such), but the compiler does not allow this conversion.
As far as I'm aware, a 2D array (or higher number of dimensions) is laid out in contiguous memory, so it doesn't seem impossible that it could work somehow. Using unsafe and fixed can allow access through a pointer, but this doesn't help with returning the array as 1D.
While I believe I can just use a 1D array throughout in the case I'm working on at present, it would be useful if this function was part of an adapter between something which returns a multidimensional array and something else which requires a 1D one.

You can't, it's not possible in C# to convert array's this way. You maybe could do it by using a external dll ( C/C++ ), but then you need to keep your array at a fixed location.
Speed
Generally i would advice to avoid using a 2D array because theese are slow in C#, better use jagged-array or even better single dimensionals with a little bit of math.
Int32[] myArray = new Int32[xSize * ySize];
// Access
myArray[x + (y * xSize)] = 5;

In C#, arrays cannot be resized dynamically. One approach is to use System.Collections.ArrayList instead of a native array. Another (faster) solution is to re-allocate the array with a different size and to copy the contents of the old array to the new array. The generic function resizeArray (below) can be used to do that.
One example here :
// Reallocates an array with a new size, and copies the contents
// of the old array to the new array.
// Arguments:
// oldArray the old array, to be reallocated.
// newSize the new array size.
// Returns A new array with the same contents.
public static System.Array ResizeArray (System.Array oldArray, int newSize) {
int oldSize = oldArray.Length;
System.Type elementType = oldArray.GetType().GetElementType();
System.Array newArray = System.Array.CreateInstance(elementType,newSize);
int preserveLength = System.Math.Min(oldSize,newSize);
if (preserveLength > 0)
System.Array.Copy (oldArray,newArray,preserveLength);
return newArray; }

You can already iterate over a multidim as if it were a 1 dimensional array:
int[,] data = { { 1, 2, 3 }, { 3, 4, 5 } };
foreach (int i in data)
... // i := 1 .. 5
And you could wrap a 1-dim array in a class and provide an indexer property this[int x1, int x2].
But everything else will require unsafe code or copying. Both will be inefficient.

Riding on the back of Felix K.'s answer and quoting a fellow developer:
You can't convert a square to a line without losing information

try
int[,] x = {{1, 2}, {2, 2}};
int[] y = new int[4];
System.Buffer.BlockCopy(x, 0, y, 0, 4);

You cannot cast, you'll have to copy the elements:
int[] y = (from int i in y select i).ToArray();

Related

Fastest way to extend array

I am looking for fastest way to extend an array.
No matter if only for length + 1 or length + x it has to be the most fastest way.
Here is an example:
var arr = new int [200];
for(int = 0; i < 200; i++)
arr[i] = i;
And now I want to extend arr for 5 items beginning at index position 20.
var arr2 = new int [] { 999, 999, 999, 999, 999 }
How do I place arr2 inside arr by using most fast way in terms of performance?
The result shall look like this
0,1,2,3,4....20, 999, 999, 999, 999, 999, 21, 22, 23, 24....199
Create a new array which is the size you want, then use the static Array.Copy method to copy the original arrays into the new one.
You can't "extend" an array, you can only create a bigger one and copy the original into it.
Also, consider using List<int> or LinkedList<> instead of an array, unless you require extremely fine-grained control over what is in memory.
It is far easier to use List. But if you have to use arrays, you have to create new array of size 205 and copy values from both source arrays, since array size is constant.
Your best bet is to use something like List<int> rather than an array. But if you must use an array:
int[] arr1 = new int[200];
// initialize array
int[] arr2 = new int[]{999, 999, 999, 999, 999};
int targetPos = 20;
// resizes the array, copying the items
Array.Resize(ref arr1, arr1.Length + arr2.Length);
// move the tail of the array down
Buffer.BlockCopy(arr1, 4*targetPos, arr1, 4*(targetPos+arr2.Length), 4*(arr1.Length - targetPos));
// copy arr2 to the proper position
Buffer.BlockCopy(arr2, 0, 4*arr1.targetPos, 4*arr2.Length);
It might be faster to create a new array and copy the items, like this.
int[] newArray = new int[arr1.Length + arr2.Length];
// copy first part of original array
Buffer.BlockCopy(arr1, 0, newArray, 0, 4*targetPos);
// copy second array
Buffer.BlockCopy(arr2, 0, newArray, 4*targetPos, 4*arr2.Length);
// copy remainder of original array
Buffer.blockCopy(arr1, 4*targetPos, newArray, 4*(targetPos + arr2.Length), 4*(arr1.Length - targetPos));
// and replace the original array
arr1 = newArray;
Which version is faster will depend on where targetPos is. The second version will be faster when targetPos is small. When targetPos is small, the first version has to copy a lot of data twice. The second version never copies more than it has to.
BlockCopy is kind of a pain to work with because it requires byte offsets, which is the reason for all the multiplications by four in the code. You might be better off using Array.Copy in the second version above. That will prevent you having to multiply everything by 4 (and forgetting sometimes).
If you know how long the array will be dimension it to that length,
var ints = new int[someFixedLength];
If you have a vauge idea of the length, use a generic list.
var ints = new List<int>(someVagueLength);
both types implement IList but, the List type handles the redimensioning of the internal array is generically the "most fast" way.
Note: the initial .Count of the List will be 0 but, the internal array will be dimensioned to size you pass to to the constructor.
If you need to copy data between arrays, the quickest way is Buffer.BlockCopy, so from your example
Buffer.BlockCopy(arr2, 0, arr, sizeof(int) * 20, sizeof(int) * 5);
copies all 5 ints from arr2 into indecies 20, 21 ... 24 of arr.
there is no faster way to do this with c# (currently).
An answer showing timing benchmarks is given here: Best way to combine two or more byte arrays in C# . If you consider the "array you insert into " as arrays 1 and 3, and the "array to be inserted" as array 2, then the "concatenate three arrays" example applies directly.
Note the point at the end of the accepted answer: the method that is faster at creating yields an array that is slower to access (which is why I asked if you cared about speed to create, or access speed).
using System.Linq you can do the following to extend an array by adding one new object to it...
int[] intA = new int[] { 1, 2, 3 };
int intB = 4;
intA = intA.Union(new int[] { intB }).ToArray();
...or you can extend an array by adding another array of items to it...
int[] intA = new int[] { 1, 2, 3 };
int[] intB = new int[] { 4, 5, 6 };
intA = intA.Union(intB).ToArray();
...or if you don't care about duplicates...
int[] intA = new int[] { 1, 2, 3 };
int[] intB = new int[] { 4, 5, 6 };
intA = intA.Concat(intB).ToArray();

Determining size of an array of arrays in C#?

I am creating an array of arrays such that:
var arrNewArray = new string[arrOldArray.Length][7];
arrOldArray is an array of arrays such that it's [X][4], meaning the length of the 1st array or "outside" array can change, but the length of the "inside" array is ALWAYS 4, or hold 4 strings ([0][1][2][3]).
Why won't the compiler accept my statement above?
Essentially, I'm trying to take arrOldArray and expand it, or add a few more "columns" by increasing the [4] in the old array to a [7] in the new array and then copy the contents over. Perhaps I'm not doing it the best/efficient way, so any guidance would be appreciated thanks.
I think you want a two dimensional array:
var arrNewArray = new string[arrOldArray.Length, 7];
You would access it like this: arrNewArray[x, y].
This is better than a jagged array, because it clearly communicates that the number of "columns" is the same for every row.
If you want to continue using a jagged array, you need to do it like this:
var arrNewArray = new string[arrOldArray.Length][];
for(int i = 0; i < arrOldArray.Length; ++i)
arrNewArray[i] = new string[7];
The reason for this convoluted way is: With a jagged array, each "row" can have a different number of "columns". A short-hand syntax for the case where each "row" has the same number of "columns" doesn't exist. That's why your code doesn't compile.
A jagged array is essential an array of arrays, so you need to create a new array instance for each "row" of the outer array and explicitly assign it. That's what the for loop is doing.
You can't use Array.Copy with jagged arrays. Each child-array is it's own instance and Array.Copy doesn't make a deep copy, it merely copies the references from one array to another. The effect would be, that both arrays would point to the same items and changing an item in one array would be seen from the other.
You are not creating the jagged array properly. The proper way is to create the first dimension of the jagged array and then loop through the items of the first dimension to create the nested arrays and copy the data from the old arrays. Here's an example:
int newSize = 7;
string[][] newArray = new string[oldArray.Length][];
for (int i = 0; i < oldArray.Length; i++)
{
newArray[i] = new string[newSize];
Array.Copy(oldArray[i], newArray[i], oldArray[i].Length);
}
You would be wanting
var arrNewArray = new string[arrOldArray.Length, 7];
var arrNewArray = new[] {new string[7]};//array of arrays
var arrNewArray = new string[arrOldArray.Length, 7];//two-dimensional array
Using Linq:
int[][] jaggedArray2 = new int[][]
{
new int[] {1,3,5,7,9},
new int[] {0,2,4,6},
new int[] {11,22}
};
int length = jaggedArray.Sum(a => a.Length);
I don't believe what you're asking is directly possible. Because the syntax that you are using is for a jagged array, and what you are doing is effectively asking it to create a multi-dimensional array.
The syntax is confusing since it reads like what you really want is a multi-dimensional array (although I'm aware that's not the case.)
I don't believe you could store your arrays in the newly allocated array either due to a size change. You would need to build a custom copy method to move the data into the larger array.

Fastest way to chop array in two pieces

I have an array, say:
var arr1 = new [] { 1, 2, 3, 4, 5, 6 };
Now, when my array-size exceeds 5, I want to resize the current array to 3, and create a new array that contains the upper 3 values, so after this action:
arr1 = new [] { 1, 2, 3 };
newArr = new [] { 4, 5, 6 };
What's the fastest way to do this? I guess I'll have to look into the unmanaged corner, but no clue.
Some more info:
The arrays have to be able to size up without large performance hits
The arrays will only contain Int32's
Purpose of the array is to group the numbers in my source array without having to sort the whole list
In short: I want to split the following input array:
int[] arr = new int[] { 1, 3, 4, 29, 31, 33, 35, 36, 37 };
into
arr1 = 1, 3, 4
arr2 = 29, 31, 33, 35, 36, 37
but because the ideal speed is reached with an array size of 3, arr2 should be split into 2 evenly sized arrays.
Note
I know that an array's implementation in memory is quite naive (well, at least it is in C, where you can manipulate the count of items in the array so the array resizes). Also that there is a memory move function somewhere in the Win32 API. So I guess this would be the fastest:
Change arr1 so it only contains 3 items
Create new array arr2 with size 3
Memmove the bytes that aren't in arr1 anymore into arr2
I'm not sure there's anything better than creating the empty arrays, and then using Array.Copy. I'd at least hope that's optimized internally :)
int[] firstChunk = new int[3];
int[] secondChunk = new int[3];
Array.Copy(arr1, 0, firstChunk, 0, 3);
Array.Copy(arr1, 3, secondChunk, 0, 3);
To be honest, for very small arrays the overhead of the method call may be greater than just explicitly assigning the elements - but I assume that in reality you'll be using slightly bigger ones :)
You might also consider not actually splitting the array, but instead using ArraySegment to have separate "chunks" of the array. Or perhaps use List<T> to start with... it's hard to know without a bit more context.
If speed is really critical, then unmanaged code using pointers may well be the fastest approach - but I would definitely check whether you really need to go there before venturing into unsafe code.
Are you looking for something like this?
static unsafe void DoIt(int* ptr)
{
Console.WriteLine(ptr[0]);
Console.WriteLine(ptr[1]);
Console.WriteLine(ptr[2]);
}
static unsafe void Main()
{
var bytes = new byte[1024];
new Random().NextBytes(bytes);
fixed (byte* p = bytes)
{
for (int i = 0; i < bytes.Length; i += sizeof(int))
{
DoIt((int*)(p + i));
}
}
Console.ReadKey();
}
This avoids creating new arrays (which cannot be resized, not even with unsafe code!) entirely and just passes a pointer into the array to some method which reads the first three integers.
If your array will always contain 6 items how about:
var newarr1 = new []{oldarr[0], oldarr[1],oldarr[2]};
var newarr2 = new []{oldarr[3], oldarr[4],oldarr[5]};
Reading from memory is fast.
Since arrays are not dynamically resized in C#, this means your first array must have a minimum length of 5 or maximum length of 6, depending on your implementation. Then, you're going to have to dynamically create new statically sized arrays of 3 each time you need to split. Only after each split will your array items be in their natural order unless you make each new array a length of 5 or 6 as well and only add to the most recent. This approach means that each new array will have 2-3 extra pointers as well.
Unless you have a known number of items to go into your array BEFORE compiling the application, you're also going to have to have some form of holder for your dynamically created arrays, meaning you're going to have to have an array of arrays (a jagged array). Since your jagged array is also statically sized, you'll need to be able to dynamically recreate and resize it as each new dynamically created array is instantiated.
I'd say copying the items into the new array is the least of your worries here. You're looking at some pretty big performance hits as well as the array size(s) grow.
UPDATE: So, if this were absolutely required of me...
public class MyArrayClass
{
private int[][] _master = new int[10][];
private int[] _current = new int[3];
private int _currentCount, _masterCount;
public void Add(int number)
{
_current[_currentCount] = number;
_currentCount += 1;
if (_currentCount == _current.Length)
{
Array.Copy(_current,0,_master[_masterCount],0,3);
_currentCount = 0;
_current = new int[3];
_masterCount += 1;
if (_masterCount == _master.Length)
{
int[][] newMaster = new int[_master.Length + 10][];
Array.Copy(_master, 0, newMaster, 0, _master.Length);
_master = newMaster;
}
}
}
public int[][] GetMyArray()
{
return _master;
}
public int[] GetMinorArray(int index)
{
return _master[index];
}
public int GetItem(int MasterIndex, int MinorIndex)
{
return _master[MasterIndex][MinorIndex];
}
}
Note: This probably isn't perfect code, it's a horrible way to implement things, and I would NEVER do this in production code.
The obligatory LINQ solution:
if(arr1.Length > 5)
{
var newArr = arr1.Skip(arr1.Length / 2).ToArray();
arr1 = arr1.Take(arr1.Length / 2).ToArray();
}
LINQ is faster than you might think; this will basically be limited by the Framework's ability to spin through an IEnumerable (which on an array is pretty darn fast). This should execute in roughly linear time, and can accept any initial size of arr1.

LINQ: transform an array [,] into array[]

I know this is kind of a dumb question, but does anyone have an elegant (or non-elegant) LINQ approach to transform a 2D array (object[,]) into a 1D array (object[]) comprised of the first dimension of the 2D array?
Example:
// I'd like to have the following array
object[,] dim2 = {{1,1},{2,2},{3,3}};
// converted into this kind of an array... :)
object[] dim1 = { 1, 2, 3 };
You claim that you want a 1D array (object[]) comprised of the first dimension of the 2D array, so I assume you are trying to select a subset of the original 2D array.
int[,] foo = new int[2, 3]
{
{1,2,3},
{4,5,6}
};
int[] first = Enumerable.Range(0, foo.GetLength(0))
.Select(i => foo[i, 0])
.ToArray();
// first == {1, 4}
#Elisha had posted an answer (didn't compile initially) also, which I was investigating this afternoon. I don't know why he deleted his answer, but I carried on with his code example until everything got worked out, and it also gives me what I need:
object[,] dim2 =
{{"ADP", "Australia"}, {"CDN", "Canada"}, {"USD", "United States"}};
object[] dim1 = dim2.Cast<object>().ToArray();
// dim1 = {"ADP", "CDN", "USD"}
This code compiles and returns the expected results. I glad about the .Cast(), and that I only needed the first dimension, not the second.
In general, for a collection of collections (instead of an array of arrays), you can do:
mainCollection.Select(subCollection => subCollection.First());

Define a double array without a fixed size?

Hello i have a problem with c# Arrays. I need a array to store some data in there...
My Code is that
double[] ATmittelMin;
ATmittelMin[zaehlMittel] = Gradient(x, xATmax, y, yATmax);
But the compiler says: not defined var
How can i define a double array without a fixed size ?
Thanks a lot!
Arrays are always fixed in size, and have to be defined like so:
double[] items1 = new double[10];
// This means array is double[3] and cannot be changed without redefining it.
double[] items2 = {1.23, 4.56, 7.89};
The List<T> class uses an array in the background and redefines it when it runs out of space:
List<double> items = new List<double>();
items.Add(1.23);
items.Add(4.56);
items.Add(7.89);
// This will give you a double[3] array with the items of the list.
double[] itemsArray = items.ToArray();
You can iterate through a List<T> just as you would an array:
foreach (double item in items)
{
Console.WriteLine(item);
}
// Note that the property is 'Count' rather than 'Length'
for (int i = 0; i < items.Count; i++)
{
Console.WriteLine(items[i]);
}
From what I see you did not declare the zaehlMittel variable. I guess this is what the compiler complains about.
Apart from that, even though you can of course determine the value of that variable programmatically, the moment you want to create an array its size must be known. This is the way arrays work.
In case you cannot do that easily, I suggest using some sort of dynamic datastructure, like a list or a set. Then, once all elements have been added, you are of course still free to create an array from that, as by that time you know the number of elements (even though there are convenience methods like toArray() that will even take care of that).
You have to instanciate the array before using it:
double[] ATmittelMin = new double[10];
ATmittelMin[zaehlMittel] = Gradient(x, xATmax, y, yATmax);
The obvious solution that springs to mind is to use a List:
List<double> ATmittelMin = new List<double>();
ATmittelMin.Add(Gradient(x, xATMax, y, yATMax);
But if you don't want to convert from a list to an array you can grow the array later:
double[] ATmittelMin = new double[10];
// Some code
int index = some_value;
if (index >= TmittelMin.Length)
{
Array.Resize(ATmittelMin, index+5); // So we're not constantly resizing the array
}
It's not ideal as you're doing a lot of the work that List is doing behind the scenes - probably a lot more efficiently than you can.

Categories

Resources