I want to do something like this.
The array itself needs to be a single dimensional array but it's elements must hold different multidimensional arrays
Looks like you want something like this:
int[][,] array = new[]
{
new int[2, 2],
new int[3, 3],
new int[4, 4]
};
foreach (var table in array)
{
for (int j = 0; j < table.GetLength(1); j++)
for (int i = 0; i < table.GetLength(0); i++)
table[i, j] = i * j; // feed in some value
}
Documentation (loop up jaggedArray4 example).
You could consider not working with raw arrays, but encapsulate the matrices into a separate class. This way your code will be more readable.
Related
How do I convert a multi-dimensional array of int into a multi-dimensional dictionary using Lambda?
For example I would like to convert Test1 (int[2,3]) into Test 3 (Dictionary<(int,int),int>)
int[,] Test1 = new int[2, 3];
int k = 0;
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
Test1[i, j] = k++;
}
}
I can easily convert it into dictionary using the traditional way with the "for - next" loop but when I tried using lambda:
Dictionary<(int,int),int>Test3 = Enumerable.Range(0, Test1.Length)
.ToDictionary((int i ,int j )=>new { z =Test1[i, j] });
I got the syntax error below:
Error CS0411 The type arguments for method 'Enumerable.ToDictionary<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
How do I specify the type arguments explicitly?
Unfortunately you can't easily use Linq to loop through "rows" of a 2-D array, since the iterator for a square array just loops through the elements. You'll need to use an old-fashion for loop:
var Test3 = new Dictionary<(int,int),int>();
for (int i = 0; i < Test1.GetLength(0); i++)
{
Test3[(Test1[i, 0], Test1[i, 1])] = Test1[i, 2];
}
This assumes that the pairs in the first two "columns" are unique, otherwise the last one would "win".
You could use Linq to enumerate through the rows by usinng Range over one axis as you tried to do:
Dictionary<(int,int),int>Test3 = Enumerable
.Range(0, Test1.GetLength(0))
.ToDictionary(i => (Test1[i, 0], Test1[i, 1]), i => Test1[i, 2]);
Note that the lambdas in ToDictionary define the key and value, respectively.
but the for loop is cleaner and easier to understand in my opinion.
I have 2 tables with random numbers and i want to check which number from first table doesn't exist in second one and output it.
Example:
First table: 2, 6, 7, 9
Second table: 0, 6, 11, 3
Output: 2, 7, 9
My current code:
#region CompareTables
int[,] TABLE1 = new int[5, 10];
int[,] TABLE2 = new int[5, 10];
Random rnd = new Random();
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 10; j++)
{
TABLE1[i, j] = rnd.Next(1, 100);
TABLE2[i, j] = rnd.Next(1, 100);
}
}
Console.Write("TABLE1" + "\n\n");
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 10; j++)
Console.Write(TABLE1[i, j] + " " + "\t");
Console.WriteLine();
}
Console.Write("\n");
Console.Write("TABLE2" + "\n\n");
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 10; j++)
Console.Write(TABLE2[i, j] + " " + "\t");
Console.WriteLine();
}
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 10; j++)
if (TABLE1[i, j] == TABLE2[i, j])
Console.WriteLine();
}
Console.ReadKey();
#endregion
I would like to ask how to output numbers that are in first table but not in second?
The problem you are having is that your tables are 2 dimensional arrays and you are trying to index into them as if they were one dimensional arrays.
Look at how your are filling them up:
TABLE1[i, j] = rnd.Next(1, 100);
TABLE2[i, j] = rnd.Next(1, 100);
You are correctly using two indexes i and j (think of rows and columns).
However, later on you are doing:
if (TABLE1[1] == TABLE2[i]) //where is the second index?
This is obviously wrong, but instead of making this work, lets take a step back and think this through again. All this mucking around with two indexes seems a little... yeah, mucky, shouldn't there be a better way to do this?
In your current problem, the fact that the tables are multidimensional is simply a pain that doesn't really add any value. If you only need to return elements of the first table that are not present in the second table without any position information, then why all this hassle with indexes to begin with? Lets create a helper method that flattens the arrays and enables us to get rid of at least one index:
static IEnumerable<T> Flatten<T>(this T[,] array)
{
for (var i = 0; i < array.GetLength(0); i++)
for (var j = 0; j < array.GetLength(1); j++)
yield return array[i, j];
}
And now that we have one dimensional arrays (IEnumerable<T>s) we can leverage C#'s magic stick...LINQ! Solving your problem is as simple as:
var notPresent = TABLE1.Flatten().Except(TABLE2.Flatten());
But this can have horrible performance if the arrays are big enough. Remember how you would solve this problem by hand (and how Except does it too): take first element from table 1, check all elements from table 2 until you either find a match or there are no more elements. Take second element from table 1, check all elements from table 2 until... etc. That seems a lot of work, and it grows really fast if the tables are big. Also if your are not smart about it you might be doing unnecessary extra work because Table 1 and 2 might contain duplicate elements...
Can this be improved? Yes, there are specially built collections that allow really fast searches; Sets. In your case, a HashSet<int> seems like a pretty good choice.
Your code now would look like:
var set = new HashSet<int>(TABLE1.Flatten());
var notPresent = set.Except(TABLE2.Flatten());
And this will perform much better.
You could covert your 2D arrays into lists and find the numbers from TABLE1 that don't exist in TABLE2 with LINQ Except:
List<int> LIST1 = TABLE1.Cast<int>().ToList();
List<int> LIST2 = TABLE2.Cast<int>().ToList();
var result = LIST1.Except(LIST2);
Consider the following array:
private int[][] Blocks;
How can I specify each of this array's sizes separately?
Something like so was my first idea: (throws an error though)
Blocks = new int[5][];
Blocks = new int[][7];
Errors come as following:
Wrong number of indices inside []; expected 1
Array creation must have array size or array initializer
Invalid rank specifier ',' or ']'
There are two ways of declaring arrays in two dimensions.
True 2-dimensional arrays
Jagged arrays
A two dimensional array is one single array with two dimensions, i.e. one matrix. It has a rectangular shape:
int[,] twoDimensionalArray = new int[5, 7];
You can loop through all elements of a two dimensional array like this:
for (int i = 0; i < twoDimensionalArray.GetLength(0); i++) {
for (int j = 0; j < twoDimensionalArray.GetLength(1); j++) {
int element = twoDimensionalArray[i, j];
// TODO: Do something with element.
}
}
If the array is of constant size, declare constants for the size:
const int ArrWidth = 5, ArrHeight = 7;
int[,] twoDimensionalArray = new int[ArrWidth, ArrHeight];
for (int i = 0; i < ArrWidth; i++) {
for (int j = 0; j < ArrHeight; j++) {
int element = twoDimensionalArray[i, j];
// TODO: Do something with element.
}
}
You can also enumerate all elements of a multi-dimensional array as a flattened enumeration with foreach:
foreach (int element in twoDimensionalArray) {
// TODO: Do something with element.
}
A jagged array is an array of arrays. You must create the array in two steps:
// First create the base (or outer) array
int[][] jaggedArray = new int[5][];
// Then create the nested (or innner) arrays
jaggedArray[0] = new int[7];
jaggedArray[1] = new int[2];
jaggedArray[2] = new int[11];
jaggedArray[3] = new int[0];
jaggedArray[4] = new int[4];
Because the nested arrays can have different sizes, this type of array is called "jagged".
You can loop through all elements of a jagged array like this:
for (int i = 0; i < jaggedArray.Length; i++) {
int[] inner = jaggedArray[i];
if (inner != null) {
for (int j = 0; j < inner.Length; j++) {
int element = inner[j];
// TODO: Do something with element.
}
}
}
You can leave out the null-test, if you know that you have initialized all inner arrays.
This
int[][] blocks = ...
is an array of arrays.
what you want probably, is a 2-dimensional array, which is declared like this:
int[,] blocks = new int[5,7];
If you really want an array of arrays, you can only declare the first 'dimension' like this:
int[][] block = new int[5][];
This creates an array of 5 (nulls).
Now you have to create each of those 'subarrays' like this:
block[0] = new int[3];
block[1] = new int [20];
The dieffernece here is, that each "subarray" can have a totally different size, compared to the 2-dimensional array.
what do you declare is an array of arrays so you have two cases.
Blocks = new int[5][];
the first is the size of the content of the array have same dimension
for (int i = 0; i < Blocks.Length; i++)
Blocks[i] = new int[8];
the second is the size of the content of the array have different dimension:
Blocks[0] = new int[6];
Blocks[1] = new int[4];
Blocks[2] = new int[10];
Blocks[3] = new int[7];
Blocks[4] = new int[3];
i have array that call nums, it contain int var.
the array is 2d -
int[,] nums = new int[lines, row];
i need to print each line in the array in other line.
when i try to print to array like this:
for (int i = 0; i < lines; i++)
for (int j = 0; j < 46; j++)
Console.Write(nums[i,j]);
** when i using the above syntax i dont get an error in visual studio, but when i run the program, i got error in this line - Console.Write(nums[i,j]);.
error - system.IndeOutOfRangeException.
i got the error , i try to change the syntax to this:
for (int i = 0; i < lines; i++)
for (int j = 0; j < 46; j++)
Console.Write(nums[i][j]);
the error: "wrong number of indices inside []; expected 2"
and:
for (int i = 0; i < lines; i++)
for (int j = 0; j < 46; j++)
Console.Write(nums[i][j].tostring());
update
i am so stupid... i write 46(number in my program) instead of 6(numbers in each row) thats whey is was out of range.
ty for all, and i am sry to open a question with such bad problem...
TY!
If lines and row are positive integer values, say, int lines = 5; int row = 7; you can print out your table like this:
int[,] nums = new int[lines, row]; // <- Multidimensional (2 in this case) array, not an array of array which is nums[][]
//TODO: fill nums with values, otherwise nums will be all zeros
for (int i = 0; i < lines; i++) {
Console.WriteLine(); // <- let's start each array's line with a new line
for (int j = 0; j < row; j++) { // <- What the magic number "46" is? "row" should be here...
Console.Write(nums[i, j]); // <- nums[i, j].ToString() doesn't spoil the output
if (j > 0) // <- let's separate values by spaces "1 2 3 4" instead of "1234"
Console.Write(" ");
}
}
You are dealing with 2 different types of arrays
int[,] nums = new int[lines, row];
is a Multi-Dimensional Array. Elements of the array can be accessed using nums[x,y].
When you use nums[x][y] you are dealing with an array of arrays.
You cannot use array of arrays syntax with a multi-dimensional array.
You might try What are the differences between Multidimensional array and Array of Arrays in C#? for details.
I'm trying to write a code that will fill array with unique numbers.
I could write the code separately for 1, 2 and 3 dimensional arrays but number of for cycles grow to "infinity".
this is the code for 2D array:
static void fillArray(int[,] array)
{
Random rand = new Random();
for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
{
array[i, j] = rand.Next(1, 100);
for (int k = 0; k < j; k++)
if (array[i, k] == array[i, j])
j--;
}
}
print_info(array);
}
Is it possible to do something like this for n-dimensional arrays?
My approach is to start with a 1-d array of unique numbers, which you can shuffle, and then slot into appropriate places in your real array.
Here is the main function:
private static void Initialize(Array array)
{
var rank = array.Rank;
var dimensionLengths = new List<int>();
var totalSize = 1;
int[] arrayIndices = new int[rank];
for (var dimension = 0; dimension < rank; dimension++)
{
var upperBound = array.GetLength(dimension);
dimensionLengths.Add(upperBound);
totalSize *= upperBound;
}
var singleArray = new int[totalSize];
for (int i = 0; i < totalSize; i++) singleArray[i] = i;
singleArray = Shuffle(singleArray);
for (var i = 0; i < singleArray.Length; i++)
{
var remainingIndex = i;
for (var dimension = array.Rank - 1; dimension >= 0; dimension--)
{
arrayIndices[dimension] = remainingIndex%dimensionLengths[dimension];
remainingIndex /= dimensionLengths[dimension];
}
// Now, set the appropriate cell in your real array:
array.SetValue(singleArray[i], arrayIndices);
}
}
The key in this example is the array.SetValue(value, params int[] indices) function. By building up the correct list of indices, you can use this function to set an arbitrary cell in your array.
Here is the Shuffle function:
private static int[] Shuffle(int[] singleArray)
{
var random = new Random();
for (int i = singleArray.Length; i > 1; i--)
{
// Pick random element to swap.
int j = random.Next(i); // 0 <= j <= i-1
// Swap.
int tmp = singleArray[j];
singleArray[j] = singleArray[i - 1];
singleArray[i - 1] = tmp;
}
return singleArray;
}
And finally a demonstration of it in use:
var array1 = new int[2,3,5];
Initialize(array1);
var array2 = new int[2,2,3,4];
Initialize(array2);
My strategy assigns sequential numbers to the original 1-d array to ensure uniqueness, but you can adopt a different strategy for this as you see fit.
You can use Rank property to get the total number of dimentions in your array
To insert use SetValue method
In the first two for loops you are analysing the array properly (i and j go from the start to the end of the corresponding dimension). The problem comes in the most internal part where you introduce a "correction" which actually provokes an endless loop for j.
First iteration:
- First loop: i = 0;
- Second loop: j = 0;
- Third loop: j = -1
Second iteration
- First loop: i = 0;
- Second loop: j = 0;
- Third loop: j = -1
. etc., etc.
(I start my analysis in the moment when the internal loop is used for the first time. Also bear in mind that the exact behaviour cannot be predicted as far as random numbers are involved. But the idea is that you are making the j counter back over and over by following an arbitrary rule).
What you want to accomplish exactly? What is this last correction (the one provoking the endless loop) meant to do?
If the only thing you intend to do is checking the previously stored values, you have to rely on a different variable (j2, for example) which will not affect any of the loops above:
int j2 = j;
for (int k = 0; k < j2; k++)
if (array[i, k] == array[i, j2])
j2--;