Arrays, different size column and rows throws IndexOutOfRangeException - c#

The program I'm writing, is suppose to create an array, read its size and inputs from an .txt-file.
Print it out in a new .txt-file, with the transpose of the matrix(array) and the max-value in the array.
The content of the .txt-file is like a downward list. The first two numbers are to set the sizes of the arrays, the following numbers below are the numbers inside it.
The code works almost as I want it.. as of now, it can read arrays with the same length of columns and rows - as in 5x5, 8x8 etc. print out the transpose and find the max-value.
Here's the problem
But I need it to also be able to make arrays the size of 3x4, 4x5, 5x8 etc, and do all the things i mentioned above.
I'm greeted with the error System.IndexOutOfRangeException as I try to run it.
Here's how my code looks right now: Full Code Example
int column = Convert.ToInt32(sr.ReadLine()); //Reads value from txt
int row = Convert.ToInt32(sr.ReadLine()); //Reads value from txt
int[,] Matris = new int[row, column]; //Creates 2D array
//For-loop for "input"
for (int i = 0; i < column; i++)
{
for (int j = 0; j < row; j++)
{
Matris[i, j] = Convert.ToInt32(sr.ReadLine()); //Saves values to array. HERE'S WHERE I GET THE ERROR.
}
}

row and column are swapped. Make the declaration of the array like this:
int[,] Matris = new int[column,row];
or swap the indices in the loop.

Related

How to uodate array inside a for loop and add it to a list

I am trying to update an array and add it to a list if a certain condition is true. As you can see in my code the array "rows" is updated every time inside the if condition, and the it is added to "checkList".
The problem is that when I iterate through the list to check the values, it seems that only the last value of rows has been added in every entry in the list.
Here is some code to explain
int[] rows = new int[2];
List<int[]> checkList = new List<int[]>();
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (true)
{
rows[0] = i;
rows[1] = j;
checkList.Add(rows);
}
}
}
foreach (var row in checkList)
{
Console.WriteLine(row[0] + " " + row[1]);
}
Output:
I hope someone can explain this. Thanks
Most object types in .NET (including arrays) are passed by reference, so checkList.Add(rows); adds a reference to the same array to the list, multiple times.
Instead, you'll want to create a new array instance every time:
List<int[]> checkList = new List<int[]>();
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (true)
{
checkList.Add(new int[]{ i, j });
}
}
}
I believe the issue here is that when you are
checkList.Add(rows);
You are adding a reference to the rows array every time to the list, not a separate copy of it. This leads to your current behaviour.
A solution would be to instantiate the array inside the loop, so a new array is created every iteration.
List<int[]> checkList = new List<int[]>();
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (true)
{
int[] rows = new int[2];
rows[0] = i;
rows[1] = j;
checkList.Add(rows);
}
}
}
As a supplement to Matthias answer, one of the things that's perhaps not easy to appreciate about C# is that most variables you have and use are merely a reference to something else. When you assign some variable like this:
int[] rows = new int[2];
C# creates some space in memory to keep an array of 2 integers, it attaches a reference to it, and that thing becomes your variable that you use, named rows. If you then do:
int[] rows2 = rows;
It doesn't clone the memory space used and create a new array, it just creates another reference attached to the same data in memory. If the data were a dog, it now has 2 leads attached to its collar but there is still only one dog. You can pull on either lead to urge the dog to stop peeing on a car, but it's the same dog you're affecting.
Array/list slots are just like variables in this regard. To say you have:
List<int[]> checkList = new List<int[]>();
Means declare a list where each of its slots are a variable capable of referring to an int array. It's conceptually no different to saying:
int[] checkList0 = row;
int[] checkList1 = row;
int[] checkList2 = row;
int[] checkList3 = row;
It's just that those numbers are baked into the name, whereas a list permits you a way of varying the name programmatically (and having more than 4 slots):
checkList[0] = row;
checkList[1] = row;
checkList[2] = row;
checkList[3] = row;
checkList[0] is conceptually the entire variable name, just like checkList0 is a variable name, and remember that this is hence just another variable that is just a reference to that same array in memory.
By not making a new array each time, you attached every variable slot in the list to the same array in memory, and thus you ended up with something in memory that looks like:
The black is the list, the blue is the array. Every list slot is just a reference to the same array. You might have changed the numbers in the array 200 times, but at the end of the oepration, because there was only ever one array, you only see the final set of numbers you wrote into the array. You might have attached 20 leads to your dog and pulled each of them once, but it's still just the same dog that has 20 times been stopped from peeing on 20 cars.
Matthias answer works (and is how it should be done) because you concretely make a new array each time
Numbers in blue are fabricated and not intended to represent the answers you should see printed; the concept being explained is that of linking to new array objects in memory
You'd be forgiven for thinking that a clone would be made, bcause it is for int. int is a value type, whcih means the value is copied when it's used:
int x = 1;
int y = x;
y = y + 1;
y is now 2, but x is still 1. It'd be pretty hard work to write C# if it wasn't this way i.e. if every time you incremented some int variable, every other variable that had touched the variable that it came from was also affected.. So I think it's perhaps intrinsically reasonable to assume that whenever an assignment of anything is made, changes that affect the value of the assigned variable don't affect earlier iterations of it.. but that's not the case. There's this clear divide between value types (types whose data is copied/cloned when they're assigned) and reference types (types whose data is not copied/cloned). While int is a value type (cloned), an int[] is a reference type (not cloned)
..and that's something you'll really need to get down with and remember
Roll on the what's ref/out for? query :D

How does `foreach` iterate through a 2D array?

I was curious as to how a foreach loop in C# iterates over a multidimensional array. In the following code, the second nested for loop was originally a foreach which would give the incorrect position of the pitches placed in the loop. I know it's kind of difficult to intuit what it does, but it's basically this: Pitches are put into a multidimensional array (here, numVoices is 2 and exLength is 10) so that you will have a 2x10 array of pitches; each of these rows of pitches are then played at the same time by the MIDI output device. When I used a foreach to then put the pitches' names into a string so that I could display what pitches were in what place inside of the grid, the foreach would display them in the "wrong" order (i.e., [0,3] in the pitch grid was not what was printed in the string). Using a nested for, this problem disappeared. I tried to recreate this with a smaller example of a 2D list of ints (code below) but it gives the "right" answer this time. Why?
//put pitches into grid
//numVoices = 2, exLength = 10 (10 notes long, 2 voices)
for (int i = 0; i < numVoices; i++ )
{
for(int j = 0; j < exLength; j++)
{
//here we generate random pitches in different octaves
//depending on the voice (voice 2 is in octave
//below voice 1, etc)
randnum = (random.Next(100 - (i * 13), 112 - (i * 13)));
melodyGrid[j, i] = (Pitch)randnum;
}
}
for (int i = 0; i < numVoices; i++)
{
for (int j = 0; j < exLength; j++)
{
//this down here makes it more readable for
//humans
//e.g. "FSharp5" becomes "F#5"
noteNames += String.Format("{0, -6}", melodyGrid[j,i].ToString().Replace("Sharp", "#").Replace("Flat", "b"));
}
noteNames += "\r\n"; //lower voices are just separated by newlines
}
Console.WriteLine(noteNames);
The following code works "correctly," however:
int[,] nums = { {1, 2, 3},
{4, 5, 6},
{7, 8 ,9} };
foreach (int i in nums)
{
Console.Write("{0} ", i);
}
Is it possible I was just making a semantic mistake? Or do foreach loops iterate through arrays in differing manners?
I was curious as to how a foreach loop in C# iterates over a multidimensional array.
As always for questions like this, the ultimate authority is the C# language specification. In this case, section 8.8.4:
The order in which foreach traverses the elements of an array, is as follows: For single-dimensional arrays elements are traversed in increasing index order, starting with index 0 and ending with index Length – 1. For multi-dimensional arrays, elements are traversed such that the indices of the rightmost dimension are increased first, then the next left dimension, and so on to the left.
Now, compare that with how you're iterating with your for statements:
for (int i = 0; i < numVoices; i++ )
{
for(int j = 0; j < exLength; j++)
{
...
melodyGrid[j, i] = (Pitch)randnum;
In other words, you're incrementing the leftmost dimension first... so yes, this will give a different result from foreach. If you want to use foreach but get the same iteration order, you'll need to switch the indexes for voices and length. Alternatively, if you want to keep the same order of indexes, just use the for loop and be happy with it.

C# Empty array creation

I'm having trouble with part of an array, I need to create a three dimensional array in a console program that starts empty and will have user assigned values after asking for user input. It does not need to persist past the initialization of the program.
I've created a few arrays that have values already in place to call upon, but I've never had to create an array that took the user's values that could then be called.
You can create an array of a specific size by specifying the size inside the brackets, then you can fill in the data later. Here's a sample of a three dimensional array with user-specified size.
Console.WriteLine("Enter length of arrays (three dimensions, comma separated)");
string line = Console.ReadLine();
string[] stringDimensions = line.Split(',');
int[] intDimensions = stringDimensions.Select(s => Convert.ToInt32(s)).ToArray();
var array = new string[intDimensions[0],intDimensions[1],intDimensions[2]];
for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
{
for (int k = 0; k < array.GetLength(2); k++)
{
array[i, j, k] = String.Format("{0}.{1}.{2}", i, j, k);
}
}
}
All arrays start out empty, that is all items in the array is set to the default value of the class. If it's an array of strings, for example, all items start out as null.
If it's an array of int, then all items start out as zero, so you would rather want an array of int? so that all items start out as null.
If by empty, you mean zero items, then you shouldn't use arrays, you should use a List<T>. They start out with zero items, then you add items to populate it.
Try using ArrayList:
ArrayList mainArrayList = new ArrayList();
//creating a three dimensional arraylist
mainArrayList.Add(new ArrayList());
mainArrayList.Add(new ArrayList());
mainArrayList.Add(new ArrayList());
(mainArrayList[0] as ArrayList).Capacity = userSpecifiedSizeX;
(mainArrayList[1] as ArrayList).Capacity = userSpecifiedSizeY;
(mainArrayList[2] as ArrayList).Capacity = userSpecifiedSizeZ;

Make a 2D char array scan every column for an integer value in C#

i'm trying to make a program that will scan each column of a guitar tab and play a note when it detects a number. I will do this by creating a char array and have the program scan each collumn of an int value. is this possible? if so, how do i do it?
Create a for or foreach loop that goes through each array element. When the value of interest is found, you play the note.
What will the array contain BESIDES integers? Blanks?
If nothing else, just use an int array to begin with, avoid casting from char. the "No Sound" value could be 0, or -1
But to loop through a 2D array, you would just use a nested for loop
for(int row = 0; rows > rowCount; row++)
{
for(int column = 0; column > columnCount; column ++)
{
note = yourArray[row][colum];
// do something with the note
}
}

how can I validate column names and count in an List array? C#

I'm trying to get this resolved in .NET 2.0 and unfortunately that is not negotiable.
I am reading in a csv file with columns of data that 'should' correspond to a List of tickers in IdentA with some modifications.
The csv file columsn would read:
A_MSFT,A_CSCO,_A_YHOO,B_MSFT,B_CSCO,B_YHOO,C_MSFT,C_CSCO,C_YHOO
IdentA[0]="MSFT"<br>
IdentA[1]="CSCO"<br>
IdentA[2]="YHOO"<br>
The AssetsA array is populated with the csv data<br>
AssetsA[0]=0<br>
AssetsA[1]=1.1<br>
AssetsA[2]=0<br>
AssetsA[3]=2<br>
AssetsA[4]=3.2<br>
AssetsA[5]=12<br>
AssetsA[6]=54<br>
AssetsA[7]=13<br>
AssetsA[8]=0.2<br>
The C_ columns are optional but if they exist they all need to exist. All of the suffixes must match the values in IdentA. The values in the csv files all need to be decimal.
I'm using a group of 3 as an example, there could be any number of tickers in the IdentA array.
Its easy enough to do the first part:
for (int x = 0; x < IdentA.Count; x++)
{
decimal.TryParse(AssetsA[x + IdentA.Count], out currentelections);
}
So that will get me the first set of values for the A_ columns but how can I get through B_ and C_ ? I can't do something as simple as IdentA.Count*2...
EDIT: IdentA gets populated when the first line of the csv is read, AssetsA is populated on subsequent lines until EOF. The original designer just always assumed that B_ and C_ would always exist and the data would just 'fall into place'. Going to look at what it would take to redesign it :(
use 2d arrays to go through two arrays like so
for(int i = 0; i <= twoDeeArr[0].Count-1; i++)
{
for(int j = 0; j <= twoDeeArr.Count-1; j++)
{
decimal.TryParse((decimal)twoDeeArr[i][j], out currentElections);
}
}

Categories

Resources