Out of bounds exception whilst using arrays - c#

I have an array of textboxes in which they change dyanmically depending on what the user types in. Those textboxes contain a number which represents a score of an assignment. Those score are linked to a module object. So if the user has 3 modules; 2 assignments on the first and second module and 3 assignments on the third module; then in total there would be 7 textboxes created for the user to input all their assignment marks.
What I am trying to do is to create a keyup event handler in which it gets the number in typed in by the user, and then dynamically calls a method to display the average of the the module. This is what I have so far. The following method gets called whenever the user types in a character:
public void calculateLevel4Modules(int counter) {
//iterate through modules
//iterate through assignts in that module
//whilst iterating, check tb and set userscore
//after iterating, update overall label with regards to modulecounter
//int assignmentCounter = 0;
//Console.WriteLine("in If statement.. " + counter);
for (int moduleCounter = 0; moduleCounter < requiredLevelList().Count; moduleCounter++)
{
int totalNumberOfAssignmentsInCurrentModule = requiredLevelList().ElementAt(moduleCounter).Assignments.Count;
Console.WriteLine("total number of assignmetns: " + totalNumberOfAssignmentsInCurrentModule);
assignmentCounter = assignmentCounter + totalNumberOfAssignmentsInCurrentModule;
Console.WriteLine("assignment counter: " + totalNumberOfAssignmentsInCurrentModule);
if (counter < assignmentCounter)
{
Console.WriteLine("in If statement.. " + userMarksTBLvl4[moduleCounter].Text);
try
{
int userMark = int.Parse(userMarksTBLvl4[counter].Text);
requiredLevelList().ElementAt(moduleCounter).Assignments.ElementAt(counter).UsersScore = userMark;
double modAvg = requiredLevelList().ElementAt(moduleCounter).getModuleScoreOverall();
moduleOverallLvl4[moduleCounter].Text = modAvg.ToString();
break;
}
catch (FormatException) { break; }
}
else { }
}
it works fine if the user has one module but if the user has two or more, then I get an error in the following line:
requiredLevelList().ElementAt(moduleCounter).Assignments.ElementAt(counter).UsersScore = userMark;
I am getting an out of bounds exception. I know why; its because counter is basically the # of the textbox that was typed into but by me using counter, I am accessing something not within the assignments list. This is an example of when the problem occus:
The user has 2 modules. In each module there are 2 assignments thus 4 textboxes are been created with their index ranging from 0 - 3. If the user wants to type in their score of the first assignment on the second module, its basically trying to write to the third index in that element then it crashes since that module only consist of 2 assignments.

There are some strange things in your code that make it hard to answer. First, the code you posted doesn't compile, so we have no way to test it.
Several times you use code like:
requiredLevelList().ElementAt(moduleCounter)
I assume requiredLevelList is a method that returns a list of things. There is no reason to assume requiredLevelList returns the same list, or even lists with the same number of elements, each time you call it. Maybe it does in your particular case, but this is a dangerous thing to rely on. You should use a construct like:
foreach (var module in requiredLevelList())
{
int totalNumberOfAssignmentsInCurrentModule = module.Assignments.Count;
...
module.Assignments.ElementAt(counter).UsersScore = userMark;
...
}
Code like this:
Console.WriteLine("total number of assignmetns: " + totalNumberOfAssignmentsInCurrentModule);
is symptomatic of trying to debug something after it has crashed. That is extremely inefficient. Learn how to use a debugger; you will not become an effective programmer until you know how to do this.
requiredLevelList().ElementAt(moduleCounter).Assignments.ElementAt(counter).UsersScore = userMark;
You're probably getting an out-of-bounds exception here because counter is outside the indexes of Assignments. Since you never initialize or change counter, I have no way to know what it is or should be. A debugger will tell you this, use one.
the # of the textbox that was typed into but by me using counter, I am accessing something not within the assignments list.
OK, if you're typing something “not within the assignments list” then you have to test for that and decide what to do. Perhaps something like:
if (counter >= 0 && counter < module.Assignments.Count)
module.Assignments.ElementAt(counter).UsersScore = userMark;
else
throw new Exception("I really have no idea what you want to do here.");
This also looks wrong:
moduleOverallLvl4[moduleCounter].Text = modAvg.ToString();
You never tell us what moduleOverallLvl4 is, but here you're assuming it has the same size as what is returned by requiredLevelList(). Maybe they are in this particular case, but that is a dangerous assumption. If these values are related, moduleOverallLvl4 should be contained in whatever class implements requiredLevelList, and you should have a method that assigns getModuleScoreOverall() to the correct element of moduleOverallLvl4.

Related

Recursion algorithm Stops running after finding the first Leaf node

I do apology in advance if there are many variables in the following code sample that their "types" is not clear to you, it is a big library, I just can't put all of that in here, so think of it at high-level, and the name of the variables is kind of helpful too...
Problem: A "concept" can have many "relations". Each of those relations can also have many concepts, For example like a father and child, a father has many children, a child may itsself be a father and has more children ,etc...
So I want to pass the root father and get all the hierarchy and write it to a file ...
The high-level code I am using is this, THE PROBLEM IS THAT it Crashes by a Null exception when it gets the child that has no more children. So its object is null in this line:
oUCMRConceptReltn = moTargetConceptList.ConceptReltns.get_ItemByIndex(i, false);
So I thought well let's put a not null check around it, yeah fixes the crash BUT after it sees the first leafe, it doesn't go further and algorithm stops.
So Something is wrong with the way I am calling recursion, but can't figure it out.
private void MyLoadMethod(string sConceptCKI)
{
UCMRConceptLib.UCMRConceptLoadQual oUCMRConceptLoadQual = new UCMRConceptLib.UCMRConceptLoadQual();
//Fill out UCMRConceptLoadQual object to get new list of related concepts
moTargetConceptList.Load(oUCMRConceptLoadQual;
// WHEN IT IS ZERO, THERE ARE NO MORE CHILDREN.
int numberofKids = moTargetConceptList.ConceptReltns.Count();
if (numberofKids == 0)
return ;
for (int i = 1; i <= numberofKids; i++)
{
oUCMRConceptReltn = moTargetConceptList.ConceptReltns.get_ItemByIndex(i, false);
//Get the concept linked to the relation concept
if (oUCMRConceptReltn.SourceCKI == sConceptCKI)
{
oConcept = moTargetConceptList.ItemByKeyConceptCKI(oUCMRConceptReltn.TargetCKI, false);
}
else
{
oConcept = moTargetConceptList.ItemByKeyConceptCKI(oUCMRConceptReltn.SourceCKI, false);
}
//write its name to the file...now recursion: go and find its children.
builder.AppendLine("\t" + oConcept.PrimaryCTerm.SourceString);
MyLoadMethod(oConcept.ConceptCKI);
}
return ;
}
Just as a side note, the check for number of kids being 0 is redundant, because you're never going to enter the loop.
The algorithm looks okay for what you want to do. You don't need to return anything in this case because your algorithm uses a side effect (the appendLine) to give your output.
I don't know C#, but it looks to me as if you're using some variables that are not local to the function, like oUCMRConceptReltn and oConcept. If they're not local to the function, different recursive invocations can change those values in unexpected ways. Recursive functions should almost never write to a variable outside its own scope.
Most indexes in c style languages are 0 based. So don't loop through 1 to numberofKids, loop 0 to numberofKids-1.
for (int i = 0; i < numberofKids; i++)

Can the debugger tell me a count/status of a foreach loop?

Suppose I have the following code:
List<SomeObject> someObjects = ReturnListWithThousandsOfObjects();
foreach(SomeObject someobject in someObjects)
{
DoSomething.With(someObject);
}
And also suppose that after a minute of running I put a breakpoint on DoSomething.With(someObject);.
The debugger breaks for me just fine. But now I want to know what point am I at in my iteration of the list (assume the list is unordered/has no key).
Is there a way for the debugger to say "the foreach has run 532 of 2321 iterations"?
As a debugging one off isn't there an indexof method?
i.e.
quickwatch - someObjects.indexOf(someObject);
Added - Sorry if a bit brief.
As pointed out by Guffa this will work best if the values are unique or the default equality comparer EqualityComparer function uses a unique value (such as a custom GetHashCode/Equals overload).
public class ATest
{
public int number { get; set; }
public int boo { get; set; }
public ATest()
{
}
}
protected void Go()
{
List<ATest> list = new List<ATest>();
foreach(var i in Enumerable.Range(0,30)) {
foreach(var j in Enumerable.Range(0,100)) {
list.Add(new ATest() { number = i, boo = j });
}
}
var o =0; //only for proving concept.
foreach (ATest aTest in list)
{
DoSomthing(aTest);
//proof that this does work in this example.
o++;
System.Diagnostics.Debug.Assert(o == list.IndexOf(aTest));
}
}
This is for Visual Studio, but other IDEs should have something similar:
When you set a breakpoint you can right-click it and go to "Hit Count". You can setup some parameters there ("greater than or equal to " 0 will make it work like a regular breakpoint - so would "break always"). The interesting part is the Hit Count field (which can be reset).
This can solve the "number of iterations" part. For the total number I'm afraid you're going to have to find it yourself, assuming the collection you use has such a number readily available.
You can also set the breakpoint to fire after a very large number of hits, say a few thousands/millions (I don't know what is their limit).
Then, when the "real" breakpoint fires, the one where you want to know how many times the original breakpoint was hit, you can just examine it and reset it if needed.
Is this case, if you really wanted to know what the count is, wouldn't you use a for loop?
List<SomeObject> someObjects = ReturnListWithThousandsOfObjects();
for(int someObj= 1; someObj <= someObjects.Count; someObj++)
{
Console.WriteLine(string.Format("{0} of {1} iterations", someObj, someObjects.Count));
DoSomething.With(someObject[someObj]);
}
There will be no real difference in performance between the foreach and the for loops - therefore the for loop will be a better alternative for the situation you want to achieve.
Unless you manually keep count in a variable you won't be able to easily determine this. As the loop is iterating across your collection it just uses the enumerator to grab the next element in the collection tell there are no more elements at which point it exits.
To manually keep a count you would just do:
int count = 0;
List<SomeObject> someObjects = ReturnListWithThousandsOfObjects();
foreach(SomeObject someobject in someObjects)
{
count++;
DoSomething.With(someObject);
}
Now at any point you can pause execution and see which iteration you are on
Create an extension method on List and List which accepts a Action fold, Action sideFold that let's you accumulate side effects like checking for the existence of a debugger and breaking on accumulated state.
Yes it can. Here's how [in VS 2017] :
Set a break point inside the foreach loop
Right click the break point and select 'Actions'
In the text box, enter the following: $FUNCTION {list.Items.IndexOf(item)} where 'list' is the name of your list and 'item' is the current item
Continue running the code and watch the output window

same operation but different answers(R and C#)

i have an R script that make some calculations.
and i found the same script but in C# , but it's giving me answers different than R.
the R code is :
count=16569
for(ind1 in seq(1,count,by=1000))
{
for(ind2 in seq(1,count,by=1000))
{
value=(count*(ind1^2)) + ((count*(count+1)*((2*count)+1))/6) -(2*ind1*((count*(count+1))/2)) + (2*count*ind1*(count-ind2+1)) + ((count-ind2+1)*(count^2)) + (2*count*(ind2-count-1)*(ind2+count))
}
}
and the C# code is :
double count=16569
for(int ind1=1;ind1<=count;ind1+=1000)
{
for(int ind2=1;ind2<=count;ind2+=1000)
{
value=(count*(Math.Pow(ind1,2))) + ((count*(count+1)*((2*count)+1))/6) -(2*ind1*((count*(count+1))/2)) + (2*count*ind1*(count-ind2+1)) + ((count-ind2+1)*(Math.Pow(count,2))) + (2*count*(ind2-count-1)*(ind2+count))
}
}
for the first round , the value in R is : -3032615095125
but the value in C# is : 4548002182315
what is the error ?
thanks
Looking at your code, I see that the loops won't make any difference. The values from the previous iteration of your loop are never stored or accessed, so value will always be set by the last run of the loop.
In effect, you just have three constants: count = 16569 ind1 = 16001 ind2 = 16001
And the answer is 1.209314e+12, whether or not the loops are run.
In C# (once I add semicolons and a variable declaration for value so it will run):
1209314008875
So I get the same answer in both R and C#. I know you asked why the answers are different, but you might look at whether the code is doing what you want in the first place; I'm not sure why the loops are there. With the code you've given, you could just plug-in the constants above to verify what your machine is giving you.
I don't know R, but with respect to C#, What datatype is the variable value? Could it be that the values are overflowing and therefore junk?
Check the bit sizes of your variables. The value in R looks fishy.
Also, why is count double and not int?

Do .. While loop in C#?

How do I write a Do .. While loop in C#?
(Edit: I am a VB.NET programmer trying to make the move to C#, so I do have experience with .NET / VB syntax. Thanks!)
The general form is:
do
{
// Body
} while (condition);
Where condition is some expression of type bool.
Personally I rarely write do/while loops - for, foreach and straight while loops are much more common in my experience. The latter is:
while (condition)
{
// body
}
The difference between while and do...while is that in the first case the body will never be executed if the condition is false to start with - whereas in the latter case it's always executed once before the condition is ever evaluated.
Since you mentioned you were coming from VB.NET, I would strongly suggest checking out this link to show the comparisons. You can also use this wensite to convert VB to C# and vice versa - so you can play with your existing VB code and see what it looks like in C#, including loops and anything else under the son..
To answer the loop question, you simple want to do something like:
while(condition)
{
DoSomething();
}
You can also do - while like this:
do
{
Something();
}
while(condition);
Here's another code translator I've used with success, and another great C#->VB comparison website. Good Luck!
//remember, do loop will always execute at least once, a while loop may not execute at all
//because the condition is at the top
do
{
//statements to be repeated
} while (condition);
Quite surprising that no one has mentioned yet the classical example for the do..while construct. Do..while is the way to go when you want to run some code, check or verify something (normally depending on what happened during the execution of that code), and if you don't like the result, start over again. This is exactly what you need when you want some user input that fits some constraints:
bool CheckInput(string input) { ... }
...
string input;
...
do {
input=Console.ReadLine();
} while(!CheckInput(input));
That's quite a generic form: when the condition is simple enough, it's common to place it directly on the loop construct (inside the brackets after the "while" keyword), rather than having a method to compute it.
The key concepts in this usage are that you have to request the user input at least once (in the best case, the user will get it right at the first try); and that the condition doesn't really make much sense until the body has executed at least once. Each of these are good hints that do..while is the tool for the job, both of them together are almost a guarantee.
Here's a simple example that will print some numbers:
int i = 0;
do {
Console.WriteLine(++i);
} while (i < 10);
using System;
class MainClass
{
public static void Main()
{
int i = 0;
do
{
Console.WriteLine("Number is {0}", i);
i++;
} while (i < 100);
}
}
Another method would be
using System;
class MainClass
{
public static void Main()
{
int i = 0;
while(i <100)
{
Console.WriteLine("Number is {0}", i);
i++;
}
}
}
The answer by Jon Skeet is correct and great, though I would like to give an example for those unfamiliar with while and do-while in c#:
int i=0;
while(i<10)
{
Console.WriteLine("Number is {0}", i);
i++;
}
and:
int i=0;
do
{
Console.WriteLine("Number is {0}", i);
i++;
}while(i<10)
will both output:
Number is 0
Number is 1
Number is 2
Number is 3
Number is 4
Number is 5
Number is 6
Number is 7
Number is 8
Number is 9
as we would expect. However it is important to understand that the do-while loop always executes the body the first time regardless of the check. This means that if we change i's starting value to 100 we will see very different outputs.
int i=100;
while(i<10)
{
Console.WriteLine("Number is {0}", i);
i++;
}
and:
int i=100;
do
{
Console.WriteLine("Number is {0}", i);
i++;
}while(i<10)
Now the while loop actually generates no output:
however the do-while loop generates this:
Number is 100
despite being well over 10. This is because of the unique behavior of a do-while loop to always run once unlike a regular while loop.
Apart from the Anthony Pegram's answer, you can use also the while loop, which checks the condition BEFORE getting into the loop
while (someCriteria)
{
if (someCondition)
{
someCriteria = false;
// or you can use break;
}
if (ignoreJustThisIteration)
{
continue;
}
}

Recursive woes - reducing an input string

I'm working on a portion of code that is essentially trying to reduce a list of strings down to a single string recursively.
I have an internal database built up of matching string arrays of varying length (say array lengths of 2-4).
An example input string array would be:
{"The", "dog", "ran", "away"}
And for further example, my database could be made up of string arrays in this manner:
(length 2) {{"The", "dog"},{"dog", "ran"}, {"ran", "away"}}
(length 3) {{"The", "dog", "ran"}.... and so on
So, what I am attempting to do is recursively reduce my input string array down to a single token. So ideally it would parse something like this:
1) {"The", "dog", "ran", "away"}
Say that (seq1) = {"The", "dog"} and (seq2) = {"ran", "away"}
2) { (seq1), "ran", "away"}
3) { (seq1), (seq2)}
In my sequence database I know that, for instance, seq3 = {(seq1), (seq2)}
4) { (seq3) }
So, when it is down to a single token, I'm happy and the function would end.
Here is an outline of my current program logic:
public void Tokenize(Arraylist<T> string_array, int current_size)
{
// retrieve all known sequences of length [current_size] (from global list array)
loc_sequences_by_length = sequences_by_length[current_size-min_size]; // sequences of length 2 are stored in position 0 and so on
// escape cases
if (string_array.Count == 1)
{
// finished successfully
return;
}
else if (string_array.Count < current_size)
{
// checking sequences of greater length than input string, bail
return;
}
else
{
// split input string into chunks of size [current_size] and compare to local database
// of known sequences
// (splitting code works fine)
foreach (comparison)
{
if (match_found)
{
// update input string and recall function to find other matches
string_array[found_array_position] = new_sequence;
string_array.Removerange[found_array_position+1, new_sequence.Length-1];
Tokenize(string_array, current_size)
}
}
}
// ran through unsuccessfully, increment length and try again for new sequence group
current_size++;
if (current_size > MAX_SIZE)
return;
else
Tokenize(string_array, current_size);
}
I thought it was straightforward enough, but have been getting some strange results.
Generally it appears to work, but upon further review of my output data I'm seeing some issues. Mainly, it appears to work up to a certain point...and at that point my 'curr_size' counter resets to the minimum value.
So it is called with a size of 2, then 3, then 4, then resets to 2.
My assumption was that it would run up to my predetermined max size, and then bail completely.
I tried to simplify my code as much as possible, so there are probably some simple syntax errors in transcribing. If there is any other detail that may help an eagle-eyed SO user, please let me know and I'll edit.
Thanks in advance
One bug is:
string_array[found_array_position] = new_sequence;
I don't know where this is defined, and as far as I can tell if it was defined, it is never changed.
In your if statement, when if match_found ever set to true?
Also, it appears you have an extra close brace here, but you may want the last block of code to be outside of the function:
}
}
}
It would help if you cleaned up the code, to make it easier to read. Once we get past the syntactic errors it will be easier to see what is going on, I think.
Not sure what all the issues are, but the first thing I'd do is have your "catch-all" exit block right at the beginning of your method.
public void Tokenize(Arraylist<T> string_array, int current_size)
{
if (current_size > MAX_SIZE)
return;
// Guts go here
Tokenize(string_array, ++current_size);
}
A couple things:
Your tokens are not clearly separated from your input string values. This makes it more difficult to handle, and to see what's going on.
It looks like you're writing pseudo-code:
loc_sequences_by_length is not used
found_array_position is not defined
Arraylist should be ArrayList.
etc.
Overall I agree with James' statement:
It would help if you cleaned up the
code, to make it easier to read.
-Doug

Categories

Resources