2 dimensional array in C# - c#

Can the second dimension be initialized as dynamically sizeable?

No (since C# array dimensions are fixed), but you could create an array of List<T>.

You mean a jagged array? Like this:
class Program
{
public int[][] jaggedArray = {
new int[]{ 1 } ,
new int[]{} ,
new int[]{ 1 , 2 , 3 } ,
} ;
}

Normally a jagged array has a size. You could use two collections:
List<List<int>> list = new List<List<int>>();
You can access the values the same way you would access any array. The advantage is that you don't need to specify the size at creation.
Edit: if the "outer" array is fixed, you could use:
List<int>[] list = new List<int>[100]();
Edit: looking to your example I'd say something like this could do the trick:
List<int>[] sVertRange = new List<int>[924];
int nH = 0;
for (int h = 315; h < 1240; h++)
{
for (int v = 211; v <= 660; v++)
{
Color c = bmp.GetPixel(h, v);
if (c.R > 220 && c.G < 153)
{
if(sVertRange[nH] == null)
{
sVertRange[nH] = new List<int>();
}
sVertRange[nH].Add(v);
}
nH++;
}
}

UPDATE: I just tested this and it doesn't work--it crashes immediately. So how is the following written in Kees's syntax?
int[][] sVertRange = {new int[924] ,new int[]{}};
int nH = 0;
int nV = 0;
for (int h = 315; h < 1240; h++) {
for (int v = 211; v <= 660; v++) {
Color c = bmp.GetPixel(h, v);
if (c.R > 220 && c.G < 153) {
sVertRange[nH][nV++] = v;
}
nH++;
}
}

if you want to create 2 dimensional array in C# each element type is bitmap
int num1 = 10,num2 = 20;
Bitmap[][] matrix= new Bitmap[num1][];
for (int i = 0; i < num1; i++ )
matrix[i] = new Bitmap[num2];

Related

Fill 2d array with unique random numbers from 0 to 15 C#

I can't fill it with numbers to 0 - 15 then shuffle the array, so that's not the solution
I used this code in C but now in c# it doesn't work, for some reason this code let some numbers pass the do while.
Random r = new Random();
bool unique;
int rand_num;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
do
{
unique = true;
rand_num = r.Next(16);
for (int k = 0; k < 4; k++)
{
for (int l = 0; l < 4; l++)
{
if (numbers[k, j] == rand_num)
{
unique = false;
}
}
}
} while (!unique);
numbers[i, j] = rand_num;
}
}
}
If the list of possible numbers is small, as in this case, just create the full list and randomise it first, then take the items in the order they appear. In your case, you can put the randomised numbers into a queue, then dequeue as required.
var r = new Random();
var numberQueue = new Queue<int>(Enumerable.Range(0, 16).OrderBy(n => r.NextDouble()));
var numbers = new int[4, 4];
for (var i = 0; i <= numbers.GetUpperBound(0); i++)
{
for (var j = 0; j <= numbers.GetUpperBound(1); j++)
{
numbers[i, j] = numberQueue.Dequeue();
}
}
I suggest you to use the Fisher-Yates algorithm to generate your non-repeatable sequence of random numbers.
It would be very straight-forward to implement a code to fill in a 2d array with those numbers, then.
List<int> seq = Enumerable.Range(0,16).ToList();
int[,] numbers = new int[4,4];
Random r = new();
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
int n = r.Next(0, seq.Count);
numbers[i,j] = seq[n];
seq.RemoveAt(n);
}
}
The approach you have taken may end up in continuous looping and take lot of time to complete.
Also checking for value in 2D using nested for loop is not efficient.
You can use HashSet to keep track of unique value. Searching in HashSet is fast.
following is the code approach I suggest.
var hashSet = new HashSet<int>();
var r = new Random();
var arr = new int[4, 4];
for(var i = 0;i<4;i++)
{
for(var j = 0;j<4;j++)
{
// Generate random value between 0 and 16.
var v = r.Next(0, 16);
// Check if the hashSet has the newly generated random value.
while(hashSet.Contains(v))
{
// generate new random value if the hashSet has the earlier generated value.
v = r.Next(0, 16);
}
//Add value to the hashSet.
hashSet.Add(v);
// add value to the 2D array.
arr[i, j] = v;
}
}
I hope this will help solving your issue.
The problem with your current approach is that as you get closer to the end of the array, you have to work harder and harder to get the next random value.
Imagine you roll a die, and each time you want to get a unique value. The first time you roll, any result will be unique. The next time, you have a 1/6 chance of getting a number that has already been obtained. And then a 2/6 chance, etc. and in the end most of your rolls will be non-unique.
In your example, you have 16 places that you want to fill with numbers 0 to 15. This is not a case of randomly generating numbers, but randomly placing them. How do we do this with a deck of cards? We shufle them!
My proposal is that you fill the array with unique sequential values and then shuffle them:
Random random = new Random();
int dim1 = array.GetLength(0);
int dim2 = array.GetLength(1);
int length = dim1 * dim2;
for (int i = 0; i < length; ++i)
{
int x = i / dim1;
int y = i % dim1;
array[x, y] = i; // set the initial values for each cell
}
// shuffle the values randomly
for (int i = 0; i < length; ++i)
{
int x1 = i / dim1;
int y1 = i % dim1;
int randPos = random.Next(i, length);
int x2 = randPos / dim1;
int y2 = randPos % dim1;
int tmp = array[x1, y1];
array[x1, y1] = array[x2, y2];
array[x2, y2] = tmp;
}
The shuffle in this code is based on the shuffle found here
int[,] numbers = new int[4, 4];
Random r = new Random();
bool unique;
int rand_num;
List<int> listRandom = new List<int> { };
for ( int i = 0; i < 4; i++ )
{
for ( int j = 0; j < 4; j++ )
{
do
{
unique = false;
if (!listRandom.Contains( rand_num = r.Next( 0, 16 )))
{
listRandom.Add( rand_num );
numbers[i, j] = rand_num;
unique = true;
}
} while ( !unique );
}
}

Curve fitting to a 3D polynomial with variable powers

I have 3 data sets. 2 for polynomial itself (let's call them x and y) and 1 for the function value (it's gonna be z).
Polynomial looks something like this (assuming the power of both dimensions is 3):
z = a00 + a01*x + a02*x^2 + a03*x^3 + a10*y + a11*y*x + a12*y*x^2 ... etc
I need to be able to set the power of each dimension when preparing for approximation of values of "a".
I don't really get how CurveFitting functions work with Math.NET Numerics, but i've tried Fit.LinearMultiDim and MultipleRegression.QR. I'm having trouble with initializing the Func delegate
var zs = new double[]
{
//values here
};
var x = new double[]
{
//values here
};
var y = new double[]
{
//values here. But the amounts are equal
};
var design = Matrix<double>.Build.DenseOfRowArrays(Generate.Map2(x, y,(t, w) =>
{
var list = new List<double>(); //Can i get this working?
for (int i = 0; i <= 3; i++)
{
for (int j = 0; j <= 3; j++)
{
list.Add(Math.Pow(t, j)*Math.Pow(w, i));
}
}
return list.ToArray();
}));
double[] p = MultipleRegression.QR(design, Vector<double>.Build.Dense(zs)).ToArray();
So ideally i need to be able to compose the function with some sort of loop that accounts for the max power of both variables.
UPD: The function is always above zero on any axis
I think i got it working.
Here's the code:
List<Func<double[], double>> ps = new List<Func<double[],double>>();
for (int i = 0; i <= polynomialOrderFirstVal; i++)
{
for (int j = 0; j <= polynomialOrderSecVal; j++)
{
var orderFirst = j;
var orderSecond = i;
ps.Add(d => Math.Pow(d[0], orderFirst) * Math.Pow(d[1],orderSecond));
}
}
var psArr = ps.ToArray();
double[] coefs = Fit.LinearMultiDim(x, y, psArr);

Create a dynamically dimensioned Array or List

I want to create an Array or a List with N-Dimensions.
Is there a way to do this without having a Method for each possible dimension:
private ____ createArray(int dimensions, int[] lengths)
{
// declare array with dimensions from variable dimensions
// set length of first dimension to lengths[0]
// set length of second dimension to lengths[1]
// [...]
// return array
}
And not like this
private int[][][] create3DArray(int[] lengths)
{
int[][][] array = new int[lengths[0]][][];
int[] newLengths = new int[lengths.Count - 1];
for(int i = 0; i < lengths.Count - 1; i++)
{
newLengths[i] = lengths[i + 1];
}
for(int i = 0; i < lengths[0]; i++)
{
array[i] = create2DArray(newLengths);
}
return array;
}
private int[][] create2DArray(int[] lengths)
{
int[][] array = new int[lengths[0]][];
for(int i = 0; i < lengths.Count; i++)
{
array[i] = new int[lengths[1]];
}
return array;
}
If I have to do it like this, I need to have a method for every possible (let's ignore the fact that it may not make sense to have an array with N-Dimensions) amount of dimensions.
you can create a list of lists:
var myList = new List<List<int>>();
for(int i = 0; i < 10; ++i) {
var localList = new List<int>();
myList.Add(localList);
}
You could create like this using Enumerable.Repeat as many levels as you want:
int x = 5, y = 6, z = 7;
List<List<List<int>>> list3D = Enumerable.Repeat<List<List<int>>>(
new List<List<int>>(
Enumerable.Repeat<List<int>>(
new List<int>(
Enumerable.Repeat<int>(0, z)
), y)
), x
).ToList();
}
In the example above you create 3D lists with initial value of 0 and initial size of 5x6x7
It is possible.
Make an int array of dimensions. From there, you can create a conditional var declaration. The only trick is that you need to make explicit the conversion to (Array)

Combining two double[] arrays into double[,]

I frequently have two arrays that I need to combine to one matrix (same lenght and type). I was wondering whether there is a linq way that is more elegant than:
var result = new double[dt.Count, 2];
for (int i = 0; i < dt.Count; i++)
{
result[i, 0] = dts[i];
result[i, 1] = dt[i];
}
I tried
var result = dts.zip(dt, (a,b) => new{a,b})
and:
var result = dts.Concat(dt).ToArray()
But neither do what I would like to do...
There is nothing in the framework, but here is a general solution (that works for 2 or more arrays):
public static class ArrayConvert
{
public static T[,] To2DArray<T>(params T[][] arrays)
{
if (arrays == null) throw new ArgumentNullException("arrays");
foreach (var a in arrays)
{
if (a == null) throw new ArgumentException("can not contain null arrays");
if (a.Length != arrays[0].Length) throw new ArgumentException("input arrays should have the same length");
}
var height = arrays.Length;
var width = arrays[0].Length;
var result = new T[width, height];
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
{
result[i, j] = arrays[i][j];
}
return result;
}
}
Which can then be used as follows:
var convertedArray = ArrayConvert.To2DArray(new[]{1,2,3}, new[]{4,5,6}, new[]{7,8,9});
ok then use this
class Program {
static void Main(string[] args) {
double[,] x = { { 1, 2, 3 }, { 4, 5, 6 } };
double[,] y = { { 7, 8, 9 }, { 10, 11, 12 } };
var xy = new StitchMatrix<int>(x, y);
Console.WriteLine("0,0=" + xy[0, 0]); // 1
Console.WriteLine("1,1=" + xy[1, 1]); // 5
Console.WriteLine("1,2=" + xy[1, 2]); // 6
Console.WriteLine("2,2=" + xy[2, 2]); // 9
Console.WriteLine("3,2=" + xy[3, 2]); // 12
}
}
class StitchMatrix<T> {
private T[][,] _matrices;
private double[] _lengths;
public StitchMatrix(params T[][,] matrices) {
// TODO: check they're all same size
_matrices = matrices;
// call uperbound once for speed
_lengths = _matrices.Select(m => m.GetUpperBound(0)).ToArray();
}
public T this[double x, double y] {
get {
// find the right matrix
double iMatrix = 0;
while (_lengths[iMatrix] < x) {
x -= (_lengths[iMatrix] + 1);
iMatrix++;
}
// return value at cell
return _matrices[iMatrix][x, y];
}
}
}
Here is another solution. I "prepare" the input for LINQ processing. Don't sure that this is elegant, but it is LINQ:
// the input
double[] dts = { 1, 2, 3, 4, 5 };
double[] dt = { 10, 20, 30, 40, 50 };
// list of lists, for iterating the input with LINQ
double[][] combined = { dts, dt };
var indexes = Enumerable.Range(0, dt.Length);
var subIndexes = Enumerable.Range(0, 2);
// the output
var result = new double[dt.Length, 2];
var sss = from i in indexes
from j in subIndexes
select result[i, j] = combined[j][i];
// just to activate the LINQ iterator
sss.ToList();
I suggest against doing it directly in LINQ. You can write a generic method to do it for you, something like:
public static T[,] To2DArray<T>(this T[][] arr)
{
if (arr.Length == 0)
{
return new T[,]{};
}
int standardLength = arr[0].Length;
foreach (var x in arr)
{
if (x.Length != standardLength)
{
throw new ArgumentException("Arrays must have all the same length");
}
}
T[,] solution = new T[arr.Length, standardLength];
for (int i = 0; i < arr.Length; i++)
{
for (int j = 0; j < standardLength; j++)
{
solution[i, j] = arr[i][j];
}
}
return solution;
}
I know that wasnt the question but the most elegant answer is to use f#:
let combinearrays (arr1:array<'a>) (arr2:array<'a>) =
let rws = arr1|> Array.length
Array2D.init rws 2 (fun i j -> match j with |0 -> arr1.[i] |1 -> arr2.[i])
From John see here
Here is the solution Convert two 1d Arrays in one 2D Array which I developed for my own use.
(from a1 in array1.Select((n,index)=>new{Index=index,c1=n}).ToList()
join a2 in array2.Select((n,index)=>new {Index=index,c2=n}).ToList() on a1.Index equals a2.Index
select new {c1,c2}
).ToArray()

Generic initialization of multidimensional array

I have a multidimensional array, which I want to initialize in a simple and fast way:
double[,,] arr = new double[4,5,6];
// doesn't work by design
foreach(double d in arr)
d = ... ; // my initialization value
This obviously doesn't works. But I would like to have a generic function for setting all array values to a choosen default. With own classes, I could write a special constructor, but with value types I've no real idea. With C++, I could access all items in a linear way with one for loop, but in C# I think I've to use as much for loops as I have dimensions. I've no better solution at the moment ( or I'm using unsafe code and pointer arithmetics, which would probably work.).
Is there a more elegant way for doing this ?
Not quite sure if it's what you want, but the following extension method will allow you to initialise every value in an array, regardless of the number of dimensions.
public static class ArrayExtensions
{
public static void Set<T>(this Array array, T defaultValue)
{
int[] indicies = new int[array.Rank];
SetDimension<T>(array, indicies, 0, defaultValue);
}
private static void SetDimension<T>(Array array, int[] indicies, int dimension, T defaultValue)
{
for (int i = 0; i <= array.GetUpperBound(dimension); i++)
{
indicies[dimension] = i;
if (dimension < array.Rank - 1)
SetDimension<T>(array, indicies, dimension + 1, defaultValue);
else
array.SetValue(defaultValue, indicies);
}
}
}
Use like so:
int[, ,] test1 = new int[3, 4, 5];
test1.Set(1);
int[,] test2 = new int[3, 4];
test2.Set(1);
int[] test3 = new int[3];
test3.Set(1);
I would strongly recommend using a 1D array, and map the values sequentially. You will need to convert from indeces i, j, k, ... into the proper array index, which is done with the Que() function below, part of a generic array class SeqArray<T>.
// Test code first
class Program
{
static void Main(string[] args)
{
/* 3 pages, of a 4x2 matrix
*
* |16 17|
* | 8 9|19|
* | 0 1|11|21|
* | 2 3|13|23|
* | 4 5|15|
* | 6 7|
*
* shown above are the sequential indeces for a rank 3 array
*/
SeqArray<double> arr = new SeqArray<double>(3, 4, 2);
// Initialize values to squential index "num"
int num = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
for (int k = 0; k < 2; k++)
{
arr[i, j, k] = num++;
}
}
}
// Check that the array values correspond to the index sequence
num = 0;
for (int i = 0; i < 3 * 4 * 2; i++)
{
Trace.Assert(arr.InnerArray[i] == num++);
}
// Initialize with value=π
arr = new SeqArray<double>(Math.PI, 4, 5, 6);
}
}
public class SeqArray<T>
{
T[] values;
int[] lengths;
public SeqArray(params int[] lengths)
{
this.lengths = lengths;
int N = 1;
for (int i = 0; i < lengths.Length; i++)
{
N *= lengths[i];
}
values = new T[N];
}
public SeqArray(T value, params int[] lengths) : this(lengths)
{
for (int i = 0; i < values.Length; i++)
{
values[i] = value;
}
}
public int[] Lengths { get { return lengths; } }
public int Size { get { return values.Length; } }
internal T[] InnerArray { get { return values; } }
public int Que(params int[] indeces)
{
// Check if indeces are omited like arr[4] instead of arr[4,0,0]
if (indeces.Length < lengths.Length)
{
// Make a new index array padded with zeros
int[] temp = new int[lengths.Length];
indeces.CopyTo(temp, 0);
indeces = temp;
}
// Count the elements for indeces
int k = 0;
for (int i = 0; i < indeces.Length; i++)
{
k = lengths[i] * k + indeces[i];
}
return k;
}
public T this[params int[] indeces]
{
get { return values[Que(indeces)]; }
set { values[Que(indeces)] = value; }
}
}
Here is a non-recursive version alternative to that posted by Andy Holt above:
public static void SetAll<T>(this Array array, T value)
{
var sizes = new int[array.Rank];
sizes[array.Rank - 1] = 1;
for (var d = array.Rank - 2; d >= 0; d--)
{
sizes[d] = array.GetLength(d + 1)*sizes[d + 1];
}
for (var i = 0; i < array.Length; i++)
{
var remainder = i;
var index = new int[array.Rank];
for (var d = 0; d < array.Rank && remainder > 0; d++)
{
index[d] = remainder / sizes[d];
remainder -= index[d]*sizes[d];
}
array.SetValue(value, index);
}
}

Categories