C# Out of Range in For Loop - c#

I'm running this code, but every time, I get the error "An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred" on the first line of the for loop. Its basically code for a multiple choice quiz question, with questions & answers stored in a 2d array.
Unfortunately, I can't seem to spot the problem. It's probably a simple error, but I'm a beginner so I'm struggling to spot it.
I've read through similar questions, but I don't understand why this line is causing problems. I've got 4 elements in my list, one is removed before the loop, so there should be 3 left. I'm only looping through 3 times, so I don't understand what the problem is.
Hopefully someone will be able to help, Thanks!
Random rndq = new Random();
Random rnda = new Random();
List<int> answers = new List<int> { 1, 2, 3, 4 };
int questionchoice = rndq.Next(0, questions.GetLength(0) - 1);
int labelchoice = rnda.Next(0, answers.Count-1);
lblQuestion.Text = questions[questionchoice, 0];
var answer = (Label)Controls["lblAns" + answers[labelchoice]];
answer.Text = questions[questionchoice, 1];
answers.Remove(labelchoice);
int j = 2;
for (int i = 0; i < 3; i++)
{
var wronganswers = (Label)Controls["lblAns" + answers[i]];
wronganswers.Text = questions[questionchoice, j];
answers.RemoveAt(i);
j++;
}

Each pass through the loop you're removing an item from the list. After the first pass your list has 3 items in it [2, 3, 4]. Next pass there are two items left [2, 4]. Then you try to get the third item from the list of two and get an exception.
Either you need to leave the list alone while looping or make sure that your loop condition actually references the length of the list. Assuming that you want to actually process all 4 items I would suggest that you remove the RemoveAt call completely.
Or if you actually want to remove the items, reverse the direction of your loop:
for (int i = answers.Count - 1; i >= 0; i--)
{
// ....
answers.RemoveAt(i);
}
This will still process all of the items in the list and leave you with nothing in the list at the end.

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

Placing the last member of the list on the beginning of the list

I am working on some exercises in C# and I had a task to input the list of any numbers in console and function should place the last member of the list to the first place, and shift all other members on the right.
For example, you can put "1234" in console, result should be "4123".
I tried different things and mostly to iterate through the list, but somehow I was always loosing one member of the list and i had duplicates in the new list.
After struggling for an hour or two, i decided to go easier way and I came up with the following code:
var list = new List<char>(); //this is list that is populated from console
var repositionedList = list; //this is list i am editing
char[] tempArray = new char[repositionedList.Count - 1];
for (var i = 0; i < repositionedList.Count - 1; i++)
{
tempArray[i] = repositionedList[i];
}
repositionedList[0] = repositionedList[repositionedList.Count - 1];
for (var i = 1; i < repositionedList.Count; i++)
{
repositionedList[i] = tempArray[i - 1];
}
Since I don't have any experience in coding, I am wondering if practice like this would not be acceptable. For example, I am creating new array, the most likely unnecessary and it may be costly, so there is much better way to accomplish the result.
A List in C# has some helper methods that makes this much easier:
var list = new List<char>(); //this is list that is populated from console
var lastElement = list[list.Count - 1]; // Remember what the last element is
list.RemoveAt(list.Count - 1); // Remove the last element
list.Insert(0, lastElement); // Insert the element again, but at the first index
If you are allowed to use C# lists, this would probably be the easiest solution.

How to solve argument out of range exceptions [duplicate]

This question already has answers here:
ArgumentOutOfRangeException on initialized List
(1 answer)
How to initialize a List<T> to a given size (as opposed to capacity)?
(16 answers)
Closed 4 years ago.
So I've been looking around for quite a while to try and find a solution to this.
I've been trying to make a card game and am stuck at a section in which I create a cad along with its properties. i decided to make it in the form of an array. The code looks like:
(not sure what happened with these first ones)
string[] dogs = System.IO.File.ReadAllLines(#"C:\Users\corin\Documents\C# coding\dogs.txt");
int individual = totalCards / 2;
Random r = new Random();
int Cards = totalCards / 2;
List<List<int>> playerCards = new List<List<int>>(Cards);
for (int x = 0; x < (Cards-2); x++)
{
playerCards[0].Add(Int32.Parse(dogs[x]));//Cards
playerCards[1].Add(r.Next(1, 6));//Drool
playerCards[2].Add(r.Next(1, 101));//Exercise
playerCards[3].Add(r.Next(1, 11));//Intelligence
playerCards[4].Add(r.Next(1, 11));//Friendliness
}
No errors are raised before I run the code but when I try it an Argument out of range exception occurs for the line: playerCards[0].Add(Int32.Parse(dogs[x]));
I tried removing it and the same error occured for the next line. I'm not sure what I've done wrong and have tried to find a solution for quite some time. If anyone has any tips or answers that would be great.
Thanks
try this :
string[] dogs = System.IO.File.ReadAllLines(#"C:\Users\corin\Documents\C# coding\dogs.txt");
int individual = totalCards / 2;
Random r = new Random();
int Cards = totalCards / 2;
List<List<int>> playerCards = new List<List<int>>();
//the missing piece
for (int i = 0; i < (Cards ); i++)
{
playerCards.add(new List<int>());
}
for (int x = 0; x < (Cards-2); x++)
{
playerCards[0].Add(Int32.Parse(dogs[x]));//Cards
playerCards[1].Add(r.Next(1, 6));//Drool
playerCards[2].Add(r.Next(1, 101));//Exercise
playerCards[3].Add(r.Next(1, 11));//Intelligence
playerCards[4].Add(r.Next(1, 11));//Friendliness
}
In addition to the previous answers: new List<List<int>>(Cards) doesn't do what you think it does. It sets capacity, not elementCount (or whatever it's called). When bounds are checked, elementCount is used, not capacity. capacity is useful when you have a good idea how many elements you have, to avoid reallocations and don't waste space.
So yes, before accessing by index you should add elements into the list manually.

Find remaining elements in the sequence

everyone. I've this small task to do:
There are two sequences of numbers:
A[0], A[1], ... , A[n].
B[0], B[1], ... , B[m].
Do the following operations with the sequence A:
Remove the items whose indices are divisible by B[0].
In the items remained, remove those whose indices are divisible by B[1].
Repeat this process up to B[m].
Output the items finally remained.
Input is like this: (where -1 is delimiter for two sequences A and B)
1 2 4 3 6 5 -1 2 -1
Here goes my code (explanation done via comments):
List<int> result = new List<int>(); // list for sequence A
List<int> values = new List<int>(); // list for holding value to remove
var input = Console.ReadLine().Split().Select(int.Parse).ToArray();
var len = Array.IndexOf(input, -1); // getting index of the first -1 (delimiter)
result = input.ToList(); // converting input array to List
result.RemoveRange(len, input.Length - len); // and deleting everything beyond first delimiter (including it)
for (var i = len + 1; i < input.Length - 1; i++) // for the number of elements in the sequence B
{
for (var j = 0; j < result.Count; j++) // going through all elmnts in sequence A
{
if (j % input[i] == 0) // if index is divisible by B[i]
{
values.Add(result[j]); // adding associated value to List<int> values
}
}
foreach (var value in values) // after all elements in sequence A have been looked upon, now deleting those who apply to criteria
{
result.Remove(value);
}
}
But the problem is that I'm only passing 5/11 tests cases. The 25% is 'Wrong result' and the rest 25% - 'Timed out'. I understand that my code is probably very badly written, but I really can't get to understand how to improve it.
So, if someone more experienced could explain (clarify) next points to me it would be very cool:
1. Am I doing parsing from the console input right? I feel like it could be done in a more elegant/efficient way.
2. Is my logic of getting value which apply to criteria and then storing them for later deleting is efficient in terms of performance? Or is there any other way to do it?
3. Why is this code not passing all test-cases or how would you change it in order to pass all of them?
I'm writing the answer once again, since I have misunderstood the problem completely. So undoubtly the problem in your code is a removal of elements. Let's try to avoid that. Let's try to make a new array C, where you can store all the correct numbers that should be left in the A array after each removal. So if index id is not divisible by B[i], you should add A[id] to the array C. Then, after checking all the indices with the B[i] value, you should replace the array A with the array C and do the same for B[i + 1]. Repeat until you reach the end of the array B.
The algorithm:
1. For each value in B:
2. For each id from 1 to length(A):
3. If id % value != 0, add A[id] to C
4. A = C
5. Return A.
EDIT: Be sure to make a new array C for each iteration of the 1. loop (or clear C after replacing A with it)

IndexOutOfRange Exception Thrown on Setting Int value to Array

On my app a teacher can have several classes, and when I exclude a teacher's profile I have to, first, delete his classes. I'm trying to put each class_id of this teacher on an int array, to later delete all classes which the id is contained inside this array.
This is my code so far:
int x = 0;
int[] count = new int[x];
while (reader_SelectedClasses.Read())
{
if(x != 0)
{
x++;
count = new int[x];
}
count[x] = _class.Class_id = reader_SelectedClasses.GetInt16("class_id");
}
And this is what
reader_SelectedClasses.Read()
does:
select class_id from tbl_class where user_id = " + id + ";
And this is the return, when I try this on MySQL:
But it gives me back an IndexOutOfRangeException when I run the code on my DAO class. What am I missing? Already went here but didn't quite understand. Can someone please explain on few words and post and fixed code for this?
You need to learn how to use a debugger and step through your program.
count = new int[x]; discards what was in count and creates a new array that contains zeroes. This array's indexes go from 0 to x - 1.
count[x] = ... sets the array element at index x which according to the previous line is one past the end of the array.
You need to set count = new int[x] only once, at the beginning of your program, and set count[x] = ... only if x >= 0 and x < count.Length.
You are getting IndexOutOfRange Exception because you are trying to access element from array which is out of range.
At first line you are setting x = 1. Hoping that controller enters while loop and as x is 1 it doesn't enter if loop and it executes next statement. But count[1] (x = 1) is not allowed as you have created array with only one element and that you can access with count[0]. (Array indexing starts from 0)
You are trying to achieve a List behavior with an array.
Obviously, the IndexOutOfRangeException is because you initialize an empty array and then try to add values to it in a non-existing cell.
Try to convert to List<int>:
List<int> count = new List<int>();
while (reader_SelectedClasses.Read())
{
int classId = _class.Class_id = reader_SelectedClasses.GetInt16("class_id");
count.Add(classId);
}
If you really need an array out of it you can do:
int[] countArray = count.ToArray()

Categories

Resources