Convert a C# jagged array to an array and back again - c#

I currently have a jagged array Class[][][] which I want to serialise as a normal Class[] array, then convert back into a Class[][][] array after deserialization. Is it at all possible to convert between the two both ways? The dimensions are of constant sizes.

This is how you can flatten to a 1-dimensional structure:
var jagged = new object[][][];
var flattened = jagged.SelectMany(inner => inner.SelectMany(innerInner => innerInner)).ToArray();
As for going back to multidimensional - this will depend entirely on what it is your trying to achieve/what the data represents

If you don't mind serializing a flattened array and an array of ints, you can use the following:
public static int[] JaggedSizes<T>(this T[][][] topArray)
{
List<int> rtn = new List<int>();
rtn.Add(topArray.Length);
for (int i = 0; i < topArray.Length; i++)
{
var midArray = topArray[i];
rtn.Add(midArray.Length);
for (int j = 0; j < midArray.Length; j++)
{
var botArray = midArray[j];
rtn.Add(botArray.Length);
}
}
return rtn.ToArray();
}
// Thanks #Dave Bish
public static T[] ToFlat<T>(this T[][][] jagged)
{
return jagged.SelectMany(inner =>
inner.SelectMany(innerInner => innerInner)).ToArray();
}
public static T[][][] FromFlatWithSizes<T>(this T[] flat, int[] sizes)
{
int inPtr = 0;
int sPtr = 0;
int topSize = sizes[sPtr++];
T[][][] rtn = new T[topSize][][];
for (int i = 0; i < topSize; i++)
{
int midSize = sizes[sPtr++];
T[][] mid = new T[midSize][];
rtn[i] = mid;
for (int j = 0; j < midSize; j++)
{
int botSize = sizes[sPtr++];
T[] bot = new T[botSize];
mid[j] = bot;
for (int k = 0; k < botSize; k++)
{
bot[k] = flat[inPtr++];
}
}
}
return rtn;
}

I don't think so Rory.
You may have been able to do this if it is a Class[,,] multidimensional array, but the fact that each array could be of different length is going to always be a stumbling block.
Assuming you serialize if as a Class[] + another class to give you the original dimensions, you'll be golden.

Related

Sort by selection in C#

I am a complete beginner in programming. Trying to make sorting a choice. Everything seems to be ok. Only there is one caveat. Only numbers up to 24 index are filled in the new array. I can’t understand what the problem is.
int[] Fillin(int[] mass)
{
Random r = new Random();
for(int i = 0; i < mass.Length; i++)
{
mass[i] = r.Next(1, 101);
}
return mass;
}
int SearchSmall(int[] mass)
{
int smallest = mass[0];
int small_index = 0;
for(int i = 1; i < mass.Length; i++)
{
if (mass[i] < smallest)
{
smallest = mass[i];
small_index = i;
}
}
return small_index;
}
int[] Remove(int[] massiv,int remind)
{
List<int> tmp = new List<int>(massiv);
tmp.RemoveAt(remind);
massiv = tmp.ToArray();
return massiv;
}
public int[] SortMass(int[] mass)
{
mass = Fillin(mass);
Print(mass);
Console.WriteLine("________________________________");
int[] newmass = new int[mass.Length];
int small;
for(int i = 0; i < mass.Length; i++)
{
small = SearchSmall(mass);
newmass[i] = mass[small];
mass = Remove(mass, small);
}
return newmass;
}
I think your main issue is that when you remove an element in the Remove function, the main loop in for (int i = 0; i < mass.Length; i++) will not check all elements o the initial array. A simple (and ugly) way to fix that would be not to remove the elements but to assign a very high value
public static int[] Remove(int[] massiv, int remind)
{
massiv[remind] = 999999;
return massiv;
}
Or as Legacy suggested simply modify the mass.length for newmass.lengh in the main loop.
As some others have mentioned this is not the best way to order an array, but it is an interesting exercise.

Resizing and initializing 2D array C#

I have a 2D array of type string which I want to modify and resize inside some loop. My main goal is to use minimum memory by creating a 2d array which will be modified every iteration of loop and the add a char to an appropriate cell in this array. Here is my code:
static void Main(string[] args)
{
int maxBound = 100;//length of freq array
Random rnd1 = new Random();
int numLoops = rnd1.Next(1000, 1200);//number of total elements in freq array
int[] freq = new int[maxBound];//freq array
string[,] _2dim = new string[maxBound, numLoops];//rows,columns
Random rnd2 = new Random();
for (int i = 0; i < numLoops; i++)
{
int s = rnd2.Next(maxBound);
freq[s]++;
//Here I try to add `*` to the _2dim array while resizing it to the appropriate size
}
}
What is the main approach for the solution ? Thanks
Instead of a 2D array you might want to use a jagged one. Briefly, a 2D array is always an N x M matrix, which you cannot resize, whereas a jagged array is an array of arrays, where you can separately initialize every inner element by a different size (see the differences in details here)
int maxBound = 100;
Random rnd = new Random();
int numLoops = rnd.Next(1000, 1200);
string[][] jagged = new string[numLoops][];
for (int i = 0; i < numLoops; i++)
{
int currLen = rnd.Next(maxBound);
jagged[i] = new string[currLen];
for (int j = 0; j < currLen; j++)
jagged[i][j] = "*"; // do some initialization
}
You should use a list of type string nested in a List. Then you can modify this lists. For iterating through this you should use two for loops.
List<List<string>> l = new List<List<string>> { new List<string> { "a", "b" }, new List<string> { "1", "2" } };
Iteration example:
for(int i = 0; i < l.Count; i++)
{
for(int j = 0; j < l[i].Count; j++)
{
Console.WriteLine(l[i][j]);
}
}

Get sub array from a 3D array

If I have an array:
int[,,] mainArray = new int[10,10,3];
How can I get a sub array:
int[] sub = mainArray[0,1]; // Unfortunately this doesn't work
Where sub would contain the 3 elements
sub[0] = mainArray[0,1,0];
sub[1] = mainArray[0,1,1];
sub[2] = mainArray[0,1,2];
It would be easy to write a method to do this but is there a built in way to do it?
I think you can use an extension method like this:
public static class MyExtensions
{
public static int[] GetValues(this Array source, int x, int y)
{
var length = source.GetUpperBound(2);
var values = new int[length+1];
for (int i = 0; i < length+1; i++)
{
values[i] = (int)source.GetValue(x, y, i);
}
return values;
}
}
Usage:
int[,,] mainArray = new int[10,10,3];
int[] sub = mainArray.GetValues(0, 1);
You could use nested arrays instead.
// Initialization
int[][][] mainArray = new int[10][][];
for (int i = 0; i < mainArray.Length; i++)
{
mainArray[i] = new int[10][];
for (int j = 0; j < mainArray[i].Length; j++)
{
mainArray[i][j] = new int[3];
}
}
// Usage
int[] sub = mainArray[0][1];
Yes, the initialization is a bit more complex, but other than that it's all the same. And nested arrays even have better performance (but you shouldn't care about array performance unless your profiler told you so).
Here is a helper class I wrote to help with the initialization of nested arrays.
public static class NestedArray
{
public static Array Create<T>(params int[] lengths)
{
Type arrayType = typeof(T);
for (int i = 0; i < lengths.Length - 1; i++)
arrayType = arrayType.MakeArrayType();
return CreateArray(arrayType, lengths[0], lengths.Skip(1).ToArray());
}
private static Array CreateArray(Type elementType, int length, params int[] subLengths)
{
Array array = Array.CreateInstance(elementType, length);
if (subLengths.Length > 0)
{
for (int i = 0; i < length; i++)
{
Array nestedArray = CreateArray(elementType.GetElementType(), subLengths[0], subLengths.Skip(1).ToArray());
array.SetValue(nestedArray, i);
}
}
return array;
}
}
Usage:
int[][][] mainArray = (int[][][])NestedArray.Create<int>(10, 10, 3);
Full commented source code can be found in this gist.
You can use Buffer.BlockCopy and some math, if you always want the the last dimension:
Buffer.BlockCopy(mainArray, (D2*i+j)*D3*sizeof(TYPE), sub, 0, D3*sizeof(TYPE));
will put mainArray[i,j,] in sub, where D1, D2, and D3 are your dimensions and TYPE is the type of the array elements.

Combining two single dimensional arrays in a 2D array in c#

I am having two 1D arrays. I want to convert these 2 arrays as single 2D array.
My code is:
public Static void Main()
{
int[] arrayRow;
int[] arrayCol;
for (int i = 0; i < row; i++)
{
for (int j = 0; j < column; j++)
{
int[,] myArray = new int[row,column];
myArray[i,j] = arrayRow[i]; // not possible -- your suggestions
}
}
for (int i = 0; i < row; i++)
{
for (int j = 0; j < column; j++)
{
Console.Write(myArray[i,j]);
}
}
}
I need to save arrayRow[] and arrayCol[] in myArray[,].
For example,
if we have arrayRow[]={1,2,3} and arrayCol[]={4,5,6} then myArray[,]={(1,4),(2,5),(3,6)}
Note: arrayRow and arrayCol may have different lengths. In such cases the element that have no pair should be stored in the new single dimensional array result[].
Your arrayRow[] and arrayCol[] will be just two lines of a two-dimensional array (if you didn't mean jagged one).
So the code to unite two arrays into one is just:
public static T[,] Union<T>(T[] first, T[] second) //where T : struct
{
T[,] result = new T[2, Math.Max(first.Length, second.Length)];
int firstArrayLength = first.Length * Marshal.SizeOf(typeof(T));
Buffer.BlockCopy(first, 0, result, 0, firstArrayLength);
Buffer.BlockCopy(second, 0, result, firstArrayLength, second.Length * Marshal.SizeOf(typeof(T)));
return result;
}
As it have been mentinoned, BlockCopy is cooler than for cycle.
If you do mean that you need a jagged array (like int[][]), that the solutiona will be way more simplier:
public static T[][] UnionJagged<T>(T[] first, T[] second)
{
return new T[2][] { first, second };
}
Which transforms into even simplier if we add multiple-array-as-parameters functionality:
public static T[][] UnionJagged<T>(params T[][] arrays)
{
return arrays;
}
static void Main()
{
int[] a = new int[] { 10, 2, 3 };
int[] b = new int[] { -1, 2, -3 };
int[] c = new int[] { 1, -2, 3 };
int[][] jaggedThing = UnionJagged(a, b, c);
}
Didn't tryed this, and I'm just guessing what you want to acomplish, but here it is:
int[] arrayRow;
int[] arrayCol;
int[,] myArray = new int[Math.Max(arrayRow.Length, arrayCol.Length), 2];
for (int i = 0; i < arrayRow.Length; i++)
myArray[i, 0] = arrayRow[i];
for (int i = 0; i < arrayCol.Length; i++)
myArray[i, 1] = arrayCol[i];
More performant / another way:
public static void ConvertFlatArrayToMatrix(int[] array, int[,] matrix, int dimension) {
for(int i = 0; i < array.Length; i++) {
int r = Mathf.FloorToInt(i / dimension);
int c = i % dimension;
matrix[c,r] = array[i];
}
}
This will just push the result into a 2d array you pass in.
Keep in mind, I'm not checking length or protecting against anything here, this is just the concept and the bare minimum to get the job done.

How can I convert a boxed two-dimensional array to a two-dimensional string array in one step?

Is there a way to convert a boxed two-dimensional array to a two-dimensional string array in one step using C#/.NET Framework 4.0?
using ( MSExcel.Application app = MSExcel.Application.CreateApplication() ) {
MSExcel.Workbook book1 = app.Workbooks.Open( this.txtOpen_FilePath.Text );
MSExcel.Worksheet sheet1 = (MSExcel.Worksheet)book1.Worksheets[1];
MSExcel.Range range = sheet1.GetRange( "A1", "F13" );
object value = range.Value; //the value is boxed two-dimensional array
}
I'm hopeful that some form of Array.ConvertAll might be made to work but so far the answer has eluded me.
No, I do not think you can make the conversion in one step, but I might be wrong. But you can of course create a new array and copy from the old one to the new one:
object value = range.Value; //the value is boxed two-dimensional array
var excelArray = value as object[,];
var height = excelArray.GetLength(0);
var width = excelArray.GetLength(1);
var array = new string[width, height];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
array[i, j] = excelArray[i, j] as string;
}
Edit:
Here is a two-dimensional overload of Array.ConvertAll which is not that much more complicated than the code above:
public static TOutput[,] ConvertAll<TInput, TOutput>(TInput[,] array, Converter<TInput, TOutput> converter)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if (converter == null)
{
throw new ArgumentNullException("converter");
}
int height = array.GetLength(0);
int width = array.GetLength(1);
TOutput[,] localArray = new TOutput[width, height];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
localArray[i, j] = converter(array[i, j]);
}
return localArray;
}
You can write your own ConvertAll for two-dimensional arrays:
public static TOutput[,] ConvertAll<TInput, TOutput>(
this TInput[,] array, Func<TInput, TOutput> converter)
{
int length0 = array.GetLength(0);
int length1 = array.GetLength(1);
var result = new TOutput[length0, length1];
for (int i = 0; i < length0; i++)
for (int j = 0; j < length1; j++)
result[i, j] = converter(array[i, j]);
return result;
}
string[][] strings = ((object[][])range.Value)
.Select(x => x.Select(y => y.ToString()).ToArray()).ToArray();
Edit: The clarification about object[,] instead of object[][] obviously makes this approach obsolete. An interesting problem; multidimensional arrays are quite limited.

Categories