Index was out of range error - c#

I have been looking for the reason why I get this error message for several days now! And I need help to solve this or to improve the code. It's hard to understand why this error happens and find the reason, when it just happens sometimes and not all the time! But my guess is that it has to do with the list and the numbers of items in the lists. It's in the second part of the code where the error event happens. I have also tried to add the objects that I want to remove in a special "to remove list", but why should this not work? Help is appreciated! Thanks!
public void CollisionControlMissileHitAsteroid(ContentManager content)
{
for (int i = 0; i < missilesList.Count(); i++)
{
// Stora asteroider
for (int j = 0; j < asteroidsBigList.Count(); j++)
{
if (missilesList.ElementAt(i).Bounds().Intersects(asteroidsBigList.ElementAt(j).Bounds())) // Fel här ??
{
for(int x = 0; x < 2; x++)
AddNewSmallAsteroidToList(new AsteroidSmall(content, asteroidsBigList.ElementAt(j).Position));
missilesList.RemoveAt(i);
i--;
asteroidsBigList.RemoveAt(j);
j--;
}
}
if (missilesList.Count() > 0 && asteroidsSmallList.Count > 0)
{
for (int k = 0; k < asteroidsSmallList.Count(); k++)
{
if (missilesList.ElementAt(i).Bounds().Intersects(asteroidsSmallList.ElementAt(k).Bounds())) // THIS IS WHERE THE ERROR EVENT HAPPENS!
{
missilesList.RemoveAt(i);
i--;
asteroidsSmallList.RemoveAt(k);
k--;
}
}
}
}
}
EDIT:
Is this where I should place the break? Ask beacause it still happens! I can play for five minutes until it happens!
if (missilesList.Count() > 0 && asteroidsSmallList.Count() > 0)
{
for (int k = 0; k < asteroidsSmallList.Count(); k++)
{
if (missilesList.ElementAt(i).Bounds().Intersects(asteroidsSmallList.ElementAt(k).Bounds()))
{
missilesList.RemoveAt(i);
i--;
asteroidsSmallList.RemoveAt(k);
k--;
break; // ???????
}
}
}

You are right in thinking that it's to do with the bounds of the list. I've never come up with a satisfactory way of removing listitems or array elements within a loop other than, as you say, building up a list of indexes and removing them outside of the loop.
Having said that, have you tried going through the list backwards, like -
for (int k = asteroidsSmallList.Count() - 1; k >= 0; k--)
{
...

Suppose you start off with one missile and two asteroids. The missile (i=0) hits the first asteroid (j=0) - but you're then continuing with i=-1 and j=0. You should be breaking out of the inner loop and continue with the next iteration of the outer loop there instead. After all, you're "done" with the missile - it can't hit any other asteroids, big or small.
(And yes, as per xanatos's comments, it would be more idiomatic to use the Count property instead of the Count() method.)

I think that the problem is obvious because your code runs in a for loop. In the first for loop you got i=0. Read my comments inside
for (int i = 0; i < missilesList.Count(); i++)
{
// Stora asteroider
for (int j = 0; j < asteroidsBigList.Count(); j++)
{
if (missilesList.ElementAt(i).Bounds().Intersects(asteroidsBigList.ElementAt(j).Bounds())) // Fel här ??
{
for(int x = 0; x < 2; x++)
AddNewSmallAsteroidToList(new AsteroidSmall(content, asteroidsBigList.ElementAt(j).Position));
missilesList.RemoveAt(i);
// In the first iteration of the outer for loop i=0, so what if the line below is executed
// you will get negative index Hope this help
i--;
asteroidsBigList.RemoveAt(j);
j--;
}
}

Related

How to eliminate duplicates in 2D arrays in C#

just started to learn programming and I need 2D array without duplicates. This code (well edited for 1D) worked just fine for 1D but doesn't for 2D and have no clue why.
Would be very happy if someone helped me. Thanks.
Random r = new Random();
int[,] array = new int[10, 8];
for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
{
array[i, j] = r.Next(10, 100);
for (int k = 0; k < i; k++)
{
for (int l = 0; l < j; l++)
{
if (array[i,j] == array[k,l])
{
i--;
j--;
break;
}
}
}
}
}
With the nested j loop you are filling the entire second dimension for each i, but in the k and l loops you are only checking the grid to the upper and left of current cell. You could place a number twice because you are not checking every previously filled location.
If we change the code to this:
for (int k = 0; k < array.GetLength(0); k++)
{
for (int l = 0; l < array.GetLength(1); l++)
{
if (i != k && j != l && array[i, j] == array[k, l])
{
i--;
j--;
break;
}
}
}
Then you eliminate that problem, but you very quickly find that you get a IndexOutOfRangeException because you're decrementing both i & j at the same time. That's not moving you to the previous value - it's jumping back a whole row and left one cell - and that's ultimately sending i or j to -1 and that's not good.
If you want to do it like you're attempting then you need to have a way to simply move back to the previously filled cell, regardless of the row or column you're on.
Try this:
for (int x = 0; x < array.GetLength(0) * array.GetLength(1); x++)
{
array[x % array.GetLength(0), x / array.GetLength(0)] = r.Next(10, 100);
for (int y = 0; y < x; y++)
{
if (array[x % array.GetLength(0), x / array.GetLength(0)] == array[y % array.GetLength(0), y / array.GetLength(0)])
{
x--;
break;
};
}
}
However, that's not very efficient. Try this instead:
var values = Enumerable.Range(10, 90).OrderBy(_ => r.Next()).ToArray();
for (int x = 0; x < array.GetLength(0) * array.GetLength(1); x++)
{
array[x % array.GetLength(0), x / array.GetLength(0)] = values[x];
}
So, first of all, that just seems inefficient. Not sure why you want to do it this way, but then again, don't know the reason. Looks like a programming assignment.
My guess, you need a sort of double break going on. When you break finding a match, you don't break out to the "k" for loop, so you continue looking for a match even though you found one. Try setting a boolean value to say it's found, then use that in the criteria for the for loop for k. That'll break it out and let you start over on the outside loops for i and j.
Even then, it won't work because you indescriminately subtracted i and j. So if you're on position 1,2 you will jump back to 0,1 rather than 1,2. So you need to subtract j, if it drops below 0, then subtract from i and add "array.GetLength(1)" to j.
This solution depends on HashSet's property of containing unique elements. It has an Add method that returns false when we try to add existing elements.
Random r = new Random();
int[,] array = new int[10, 8];
var usedValues = new HashSet<int>();
for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
{
int uniqueValue;
while (true)
{
uniqueValue = r.Next(10, 100);
if (usedValues.Add(uniqueValue)) break; // It is unique indeed
// It is not unique, try again.
}
array[i, j] = uniqueValue;
}
}
The above solution is more suitable when the range of the acceptable unique values is large. In this specific case the range is very small (10-99), and the solution offered by #Enigmativity is preferable.

Difference between using brackets in for loop C# and not using it

The output of the following code is different from the ouput from the second code
can someone explain the problem?
Code 1:
for(int i = 1; i <= intInput; i++)
{
for(int j = 1; j<=i; j++)
{
Console.Write('+');
Console.WriteLine();
}
}
if intInput is 4 Ouput is:
+
+
+
+
Code 2:
for(int i = 1; i <= intInput; i++)
{
for(int j = 1; j<=i; j++)
Console.Write('+');
Console.WriteLine();
}
if intInput is 4 Ouput is:
+
++
+++
++++
I know how this line of codes works but i dont understand what difference the brackets make on both codes?
When you write;
for(int j = 1; j <= i; j++)
{
Console.Write('+');
Console.WriteLine();
}
Both Console line works until j loops out.
But when you write
for(int j = 1; j <= i; j++)
Console.Write('+');
Console.WriteLine();
Only first Console works until j loops out. That's why second one is equal to;
for(int j = 1; j<=i; j++)
{
Console.Write('+');
}
Console.WriteLine();
If there is one statement included in the loop, the curly brackes can be omitted. But using them is always a better approach.
Read: Why is it considered a bad practice to omit curly braces?
You second case effectively means:
for(int i = 1; i <= intInput; i++)
{
for(int j = 1; j<=i; j++)
{
Console.Write('+');
}
Console.WriteLine();
}
Indentation means nothing for compiler it is only for you
The loop has a scope. If you do not include the braces, only the first line is in the loop. If you have the braces, everything inside falls under the scope of the loop.
In this case, the first example write a "+" to the console as well as a new line every iteration of the inner loop.
The second case, the inner loop only executes the "+" writing on each inner iteration. The outer loop adds the new line.
If alter 1 with i in second loop then it will work same
for (int j = **i**; j <= i; j++)
Console.Write('+');
Console.WriteLine();

Problems with displaying information from an array

I am trying to make a simple program in C# code (Console Application), which prompts the user to enter 10 names and then the 10 names displayed at the end in a random order (not the order the names were entered in)
This is how far I have gotten:-
static void Main(string[] args)
{
string[] names = new string [10];
int i;
for ( i = 0; i < 10 ; i++)
{
Console.WriteLine("Give me name " + (i+1) );
names[i] = Console.ReadLine();
}
for (int j = 0; j <= 10; j++)
{
Console.WriteLine(names[j]);
}
Console.ReadLine();
}
So far I have been able to prompt the user for 10 names, and store those 10 names, and display them at the end, however, once they are displayed I get the error :- "IndexOutOfRangeException was unhandled" and the Console.WriteLine(names[j]); gets highlighted.
Lastly, once these problems are sorted, how do I display the names entered back in random order?
Thanks for reading.
You get from 0 to 9 from input, but try to print from 0 to 10.
The 10th item does not exist in the array.
Correct it like below:
for (int j = 0; j < 10; j++)
{
Console.WriteLine(names[j]);
}
Hope this helps.
The first loop runs from 0 to 9, but the second runs from 0 to 10, so you try to display an item that doesn't exist in the array. Change j <= 10 to j < 10 in the loop (just like in the first loop) to loop to 9 instead of 10.
Better yet, you can use i < names.Length and j < names.Length in the loops. That way you can change the size of the array and the loops will still work without any change.
To display the items in random order you would want to shuffle the array. The best method for that is a Fisher-Yates shuffle. Shuffle the items in the array like this:
Random rnd = new Random();
for (int i = 0; i < names.Length − 1; i++) {
int j = rnd.Next(i, names.Length);
string tmp = names[i];
names[i] = names[j];
names[j] = tmp;
}
Then you can just show the items from the array the way that you do now (with the correction in the loop).
To resolve error, only check for less than 10 (<10) instead of less than or equal to 10 (<=10)
and to get random order use Random class. Make sure only one random instance is created and you call Next so that new random number is generated in tight loop
Random random = new Random();
for (int j = 0; j < 10; j++)
{
int randomNumber = random.Next(1,10);
Console.WriteLine(names[randomNumber-1]);
}
The problem is that your index is 0 based, and contains 10 entries, but the last one is Array[9] not Array[10]
{Frank,Paul,John}
So Array[0] is Frank,
and Array[3] is... out of range.
Your loop uses
for (int j = 0; j <= 10; j++)
{
Console.WriteLine(names[j]);
}
The first time through, j = 0, names[j] would be Frank for us. Your problem is since 10 <= 10 is indeed true, it is looking for j[10], which doesn't exist.
The solution is to change j < 10
for (int j = 0; j < 10; j++)
{
Console.WriteLine(names[j]);
}

Remove elements from array. index. C#. List<double>

I need your help. It's easy question, I think.
So. I work in C# with array.
var TinArr = new List<double>();
Next I have some elements in it. For example:
TinArr[0]=0.5;
TinArr[1]=0.6;
TinArr[2]=1.1;
TinArr[3]=1.5;
Ok. Then I have cycle for remove some of them:
for (var j = 0; j < TinArr.Count; j++)
{
if (TinArr[j] <= 1)
{
TinArr.RemoveAt(j);
}
}
As I understand, when I'll remove element with index "0", next element with index "1" after this action will have index "0". Maybe I'm wrong. How can I save index? Or maybe I should start cycle from the beginning? NEED YOU HELP! THANKS!
You could simply use the RemoveAll method:
TinArr.RemoveAll(x => x <= 1);
But if using a for-loop is a requirement, you should start from the end:
for (var j = TinArr.Count - 1; j >= 0; j--)
{
if (TinArr[j] <= 1)
{
TinArr.RemoveAt(j);
}
}
Do it in reverse rather, something like
for (var j =TinArr.Count - 1; j >= 0; j--)
{
if (TinArr[j] <= 1)
{
TinArr.RemoveAt(j);
}
}
You almost did it yourself, only missing post-decrement:
for (var j = 0; j < TinArr.Count; j++)
if (TinArr[j] <= 1)
TinArr.RemoveAt(j--);

C# insertion sort after each value

How can I run the Insertion Sort code after each time user enters a value. Please notice that I don't have much knowledge about programming so showing an example or ready to use code would be appreciated.
Console.Write("How long the Insertion sort list should be?: ");
var countString = Console.ReadLine();
int count = Convert.ToInt32(countString);
int[] data = new int[count];
for (int i = 0; i < count; i++)
{
var input = Console.ReadLine();
data[i] = Convert.ToInt32(input);
Console.WriteLine(input); // << HERE THE SORTING SHOULD HAPPEN AFTER EACH VALUE THAT I ADD.
}
int j = 0;
int help = 0;
for (int i = 1; i < data.Length; i++)
{
j = i;
help = data[i];
while (j > 0 && help < data[j - 1])
{
data[j] = data[j - 1];
j--;
}
data[j] = help;
}
foreach (var i in data)
{
Console.Write("{0}, ", i);
}
}
You can visually divide your code into two parts. The first part is for inserting the values. The second part sorts these values. So you have to cut the second part and insert at the place, where sorting should happen, I hope you will find this place ;)
Also think that you should replace i in the second for with something else, for example with k
Good luck

Categories

Resources