Converting <T>[][] to <T>[] by extracting 1 element from the inner array - c#

Is there a potential 1 liner that allows me to create a new 1 dimensional array from a certain index of the inner array of the 2D?
Example take the first element of each inner array:
double[][] array2D = new double[10][] // with inner arrays say double[5]
double[] array1D = new double[10];
for (int i=0; i<array2D.Length; i++)
{
array1D[i] = array2D[i][0];
}

I'd just use LINQ. That won't "avoid loops" in terms of execution, but it'll avoid a loop in your source code:
// 1dArray isn't a valid identifier...
var singleArray = jaggedArray.Select(x => x[0]).ToArray();
Note that this relies on it being a jagged array (an array of arrays). It will not do what you expect for true multi-dimensional (rectangular) arrays.
Or slightly more efficiently:
var singleArray = Array.ConvertAll(jaggedArray, x => x[0]);
That's more efficient because it knows the output size to start with, and builds the array directly - but it's a bit less idiomatic than using LINQ these days (which is more generally applicable to all sequences, not just arrays).

Related

Why can't I create a multidimensional array of arrays?

My program involves a 2-dimensional board: Square[width,height]. Each Square contains a collection of Pieces.
In the presentation layer, I want to only present the collection of Pieces in each Square and represent each Piece with its string Name. I.e. string[][width,height].
Declaring string[][,] compiles with no problem but I can't initialize the variable:
string[][,] multiArrayOfArrays; //No problemo
multiArrayOfArrays = new string[][8,8]; //Generates errors
The following errors are generated for the second line:
CS1586 Array creation must have array size or array initializer
CS0178 Invalid rank specifier: expected ',' or ']' ModChess
CS0178 Invalid rank specifier: expected ',' or ']' ModChess
I'm currently using List<string>[,] as a workaround but the errors vex me. Why can I successfully declare a string[][,] but not initialize it?
Note: Using VS Community 16.0.4, C# 7.3.
string[][,] multiArrayOfArrays; //No problemo
Here you just declare variable of specific type.
multiArrayOfArrays = new string[][8,8]; //Generates errors
And here you actually create new object of specific type. It generates errors because this is invalid syntax for multidimentional array initialization.
You need to specify size for first dimension [] and then initialize each element of that array with string[,].
Think of it as array of arrays:
string[][,] multiArrayOfArrays; //No problemo
multiArrayOfArrays = new string[5][,];//create 5 elements of string[,] array
for (int i = 0; i < multiArrayOfArrays.Length; ++i)
{
multiArrayOfArrays[i] = new string[8,8];//actually fill elements with string[8,8]
}
or
string[][,] multiArrayOfArrays; //No problemo
multiArrayOfArrays = new string[][,]
{
new string[8,8],
new string[8,8],
new string[8,8],
};
Probably you want a string[,][] a.
string[,][] a = new string[3, 4][];
a[0, 0] = new string[10];
a[0, 1] = new string[4];
a[1, 0] = new string[6];
string s = a[0, 0][2];
You have a special case of a jagged array, where the first array is 2-dimensional. It contains one-dimensional arrays of different sizes as elements.
The ordering of the array brackets might seem wrong, as the element type is usually on the left side of the brackets; however, if you think about on how you want to access elements, then it makes sense. First, you want to specify the 2 coordinates of the 2-dimensional board, then the single index of the pieces collection.
According to Jagged Arrays (C# Programming Guide), int[][,] jaggedArray4 = new int[3][,] "... is a declaration and initialization of a single-dimensional jagged array that contains three two-dimensional array elements of different sizes."

Maximum number of elements in a 2D array

I need to make an 2d array, but c# won't let me and says that it is too big, any ideas how to make it work?
int[,] arrayName = new int[37153,18366];
The max theoretical size of an int array is 2147483647 i.e. int[] array = new int[2147483647] but the probleming you're having here is that the computer runs of out memory.
Read this for explanation and tips on how to solve this:
OutOfMemoryException on declaration of Large Array
If you are not using the complete range of the array (which is in your case 2,7GB of RAM), you could use a Dictionary.
https://msdn.microsoft.com/de-de/library/xfhwa508(v=vs.110).aspx
Alternative: Create a [][] Array. In this case you must initialize each row.
But you can access each cell easy with arrayName[row][col].
int[][] arrayName = new int[37153][];
for(int i=0; i<arrayName.Length; i++)
arrayName[i] = new int[18366];

How to create a vector of strings from multi dimensional arrays?

The original problem is that I am reading big chunks of binary data from a tool that is being developed.
My goal is to read data and parse it to a human readable text such as a .csv file, so I have to flatten
that data.
The data is in form of samples of a multidimensional array of floats, longs or ints or whatever. And
because the tool is under development the size and dimensions of the array may differ from an hour to hour!
(e.g. right now I may have samples of a 2*2 matrix, two hours from now they may change the data struct to
1*4, or an array of 16*12*128,...)
One part of the problem is to generate the header line of the .CSV file. I need a method that can
generate an array of strings like this:
for a 2*2: data_0_0, data_0_1, data_1_0, data_1_1, and
for a 1*4: data_0, data_1, data_2, data_3,
for a 3*4*2: data_0_0_0, data_0_0_1, data_0_0_2,...., data_2_3_0, data_2_3_1,
and so on ...
The only information that I can get from the tool each time is the dimensions and size of the array.
The tool may tell me {1}, which means a single value, {12} means an array with a length of 12, {3,4,5}
means a " 3x4x5 " element array and so on and so forth... Therefore, I need to be able to flatten any array
of a*b*c*..*x. (which should not be too hard as I can have a single for loop.
So, I'd like to create a method that generates a vector of strings (in above format) from ANY multidimensional array.
Therefore I think at the end, the header generating method will lookalike something this
public string[] GenerateNames(string dataBlockName, int[] dimensions)
{
}
One simple solution is to have lets say 10 For-loops and hope that the raw data will never have an array that has more than 10 dimensions. However, I'm looking for a better, cleaner, nicer solution!
There are a lot of questions asking how to change a vector into multidimensional arrays. My goal is the exact opposite thing and a header line with unlimited flexibility!
Thanks a lot in advance fellas!
--
Someone below suggested to use "Depth First Traversal" which I am going to look into now. Initial googling seemed promising.
You can flatten any array by merely iterating it in a foreach loop, adding each item to a list, and then converting that list back to an array.
public T[] Flatten<T>(Array array)
{
var list = new List<T>();
foreach (T item in array)
{
list.Add(item);
}
return list.ToArray();
}
where array is a rectangular array of any shape.
You don't need the array with the size, as you can check the dimensions by using the Rank property of the Array class, and the corresponding methods for obtaining the values. With this in mind and the good old .net 1.0 Array class you can write a method like this one:
public T[] Flatten<T>(Array source)
{
var arrayIndex = new int[source.Rank];
var result = new T[Enumerable.Range(0, source.Rank).Sum(i => source.GetUpperBound(i))];
var index = 0;
for(var i = 0; i < source.Rank; i++)
{
for(var j = 0; j < source.GetUpperBound(i); j++)
{
arrayIndex[i] = j;
result[index++] = (T)source.GetValue(arrayIndex);
}
}
return result;
}
It's more convoluted than a foreach, but it will provide greater flexibility on how you could traverse the original array (which is dependent on the .net implementation). As Array is not a generic class you will need to provide the element type on the method, so that for an array of integers you can call it as:
Flatten<int>(myArray);
Buffer.BlockCopy is handy here.
Note: there are some special cases to deal with so take this as pseudocode.
public T[] Flatten<T>(Array source)
{
int byteCount = Buffer.ByteLength(source);
int sizeofT = Buffer.ByteLength(new T[1]);
T[] dest = new T[(byteCount + sizeofT - 1) / sizeofT];
Buffer.BlockCopy(source,0,dest,0,byteCount);
return dest;
}

How can I change an 2D array to a 2D list and then back to a 2D array again?

I thought searching SO would show me a hit regarding 2D lists to 2D arrays but it seems it's not as common as I had thought.
This is what I've got:
// init array
int[][] a = new int[10][10];
// change 2D array to 2D list
List<List<int>> b = a.Cast<List<int>>().ToList();
// change 2D list back to 2D array
???
How can I change b back to a 2D array? Also is the above correct?
Something like this:
List<List<int>> lists = arrays.Select(inner=>inner.ToList()).ToList();
int[][] arrays = lists.Select(inner=>inner.ToArray()).ToArray();
It's totally wrong. You can't get b in that way. And even the initialization is wrong. And in .NET there are two types of multidimensional arrays... True multidimensional arrays and jagged arrays...
Let's start... You are using a jagged array (I won't tell you what it's, or the difference, you didn't ask for it... if you need them, google for it)
int[][] a = new int[10][]; // see how you define it?
// Only the first dimension can be is sized here.
for (int i = 0; i < a.Length; i++)
{
// For each element, create a subarray
// (each element is a row in a 2d array, so this is a row of 10 columns)
a[i] = new int[10];
}
Now you have defined a 10x10 array jagged array.
Now a little LINQ:
You want a list:
List<List<int>> b = a.Select(row => row.ToList()).ToList();
you want back an array:
int[][] c = b.Select(row => row.ToArray()).ToArray();
The first expression means
foreach element of a, we call this element row `a.Select(row =>` <br>
make of this element a List `row.ToList()` and return it<br>
of all the results of all the elements of a, make a List `.ToList();`
The second is specular.
Now... Just out of curiosity, and if you had a true multidimensional array? then it was complex, very comples.
int[,] a = new int[10,10];
int l0 = a.GetLength(0);
int l1 = a.GetLength(1);
var b = new List<List<int>>(
Enumerable.Range(0, l0)
.Select(p => new List<int>(
Enumerable.Range(0, l1)
.Select(q => a[p, q]))));
var c = new int[b.Count, b[0].Count];
for (int i = 0; i < b.Count; i++)
{
for (int j = 0; j < b[i].Count; j++)
{
c[i, j] = b[i][j];
}
}
With a tricky (and horrible) LINQ expression we can "convert" a multidimensional array to a List<List<int>>. The road back isn't easily doable with LINQ (unless you want to use the List<T>.ForEach() that you shouldn't ever use, because it's not kosher, and then List<T>.ForEach() isn't LINQ)... But it's easily doable with two nested for ()

adding two int array

I have to add two int[] array in which a mian int[] array is intially vacant. I want to add the elements of another array in the main array . In the Main array, there would be more addtion that would be added in the last postion of the main array.
I have an array as -
var planetNotInRange = new int[7] ;
if(planetSign.Contains(tempFrind))
{
var result = planetSign.Select((b, k) => b.Equals(tempFrind) ? k : -1)
.Where(k => k != -1).ToArray();
// Here I want to add this result Array in to the planetNotInRange array,
// when ever there is some value in the result array.
}
this is in loop will give a number of array of integers. Now I want to concat in PLanetInRange Array one after other.
It sounds like you shouldn't have an array to start with, if you want to add elements to it. Once an array has been created, its size is fixed.
Use a List<int> instead, and you can use
list.AddRange(array);
I'd usually advise using lists (and other collection types) over arrays anyway. Arrays are useful, obviously, but they're somewhat more primitive and low-level than other collections.

Categories