calling an array index with a variable - c#

I am trying to test a specific element from a list, and compare it to a string the user inputs. It is inside an if statement:
    if (textboxinput.Text.ToString() == main.steps[current])
In this context, current is an integer equal to 0, and after the if statement is done current++.
this is a new wpf form window that is opened by clicking a button on the MainWindow wpf form. main is instantiated from the MainWindow1 class containing our list:
public List<string> steps = new List<string>();
Whenever I run this code, I receive the argument out of range exception.
In short: I am trying substitute the index of the list with a variable, and it is saying it is out of range.
Still learning c#, and this is probably an easy fix, and it's probably a super obvious rule I'm forgetting, but any help would be appreciated, as the same exception happens on arrays as well.
Here is the event for the button being clicked
int current = 0;
private void buttonanswer_Click(object sender, RoutedEventArgs e)
{
if (textboxinput.Text.ToString() == main.steps[current])
{
textboxoutput.Foreground = Brushes.Green;
textboxoutput.AppendText(textboxinput + Environment.NewLine);
textboxinput.Clear();
}
else
{
textboxoutput.Foreground = Brushes.Red;
textboxoutput.AppendText(textboxinput + Environment.NewLine);
textboxinput.Clear();
}
current++;
}

Make sure that when you're looping current, it is always less than the length of the main.steps array. Remember, if an array contains 5 elements, they are numbered 0, 1, 2, 3, and 4 for example. Most likely you are allowing current to reach the number 5 (or whatever is the size of your array in your particular case). This type of mistake would be what causes an out of bounds exception when working with an array.

Related

c# getting values from using loop like combobox[i], i++

Hello i am working on some personal project,
I have lots of comboboxes in my project, which names are combobox1,combobox2 etc..
What i am trying to do is, getting combobox.text values respectively and do some work according to this.
Here is my code below;
for (i = 1; i <= geneList.Length; i++)
{
baserequest = "/" + comboBox[i].Text + ".docx";
sources.Add(new Source(new WmlDocument(basesource + geneList[i] + baserequest), false));
baserequest="";
DocumentBuilder.BuildDocument(sources, Path.Combine(tempDi.FullName, "Output.docx"));
}
so that actually not work. I searched but i think i missearching something because all i can get is about iterating through items, but what i want to do is exactly this;
comboBox[i].Text
Thank you very much.
If your comboboxes are named comboBox1, comboBox2 .... then you can't refer to comboBox2 using a syntax like comboBox[2]. This syntax means .. give me the third combobox stored in an array of comboboxes (and that should contain at least 3 elements)
So if you really want to use this syntax you need to create that combobox array somewhere in your code. After the call to InitializeComponent for example
public class Form1: Form
{
// declare the array as a global variable
private ComboBox[] combobox;
public Form1()
{
// Create and initialize all the elements of your form
// according to the properties set in the WinForms Designer
InitializeComponent();
// Choose all the individual comboboxes that you want to use
// inside your loops in the remainder of your code
combobox = new ComboBox[] { comboBox1, comboBox2, comboBox3 };
}
// all the code of your Form1 follows.....
}
A final note: You use a different array to create your loops. This array is named geneList and it should be kept in sync with the combobox array. Meaning the two arrays should have the same number of elements otherwise (if the geneList array is bigger than the combobox one you will get an ArgumentOutOfRangeException). Also array indexing start at index 0 not 1 so the usual loop is created with this syntax
for (i = 0; i < geneList.Length; i++)
Otherwise if you start from 1, as you do now, you skip the first element in the array and the last loop searches for an element that doesn't exist.

Out of bounds exception whilst using arrays

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.

Displaying strings from Array without repeats

I working on a project in c# asp.net. I would like to randomly display a string from either an array or list, if certain conditions are met, I would like to display another random string that has not been displayed.
EX.
LIST<string> myString = new List<string> {"one", "two", "three", "four", "five"};
or
string[] myString = new[] {"one", "two", "three", "four", "five"};
void btnAnswer_Click(Object sender, EventArgs e)
{
string Next = myString[random.Next(myString.Length)];
if(my condition is met)
{
lbl.Text = Next;
}
}
I can randomly call a string from my list or array, but not sure how to store repeat results. I've tried using an algorithm that jumbles the array and then a counter for the index, but the counter (counter++) seems to add 1 once and then stops. I've tried using a list and removing the string I use, but it seems to repeat after all strings have been used.
If more code is needed I can provide, just need a point in the right direction.
One option is to display one of the random string and store it in a ViewState.
When you come next time again, check whether new random string is already there in ViewState or not. If it is there in ViewState then get another random string.
Couple of options:
Have an array or list which is a copy of the master array, and whenever you choose one, remove it from the array. Once the array is empty, refresh it from the master array.
Similar, just create your array, shuffle it, and start giving out strings by order. so array[0], next would be array[1], and so on, once you reach the end, shuffle and start again.
There are probably others as well :)
Edit:
If I understand correctly from the comments, you are talking about the option where the input is not unique to begin with. If that is the case, you can create your list with a simple linq query to get only unique values (using distinct), guaranteeing no duplicates.
Have a look at this question for an example.
You can copy the indices into a list, it will save memory while allow us to track all the remaining items:
var indices = Enumerable.Range(0,myString.Count).ToList();
//define some method to get next index
public int? NextIndex(){
if(indices.Count == 0) return null;
int i = random.Next(indices.Count);
int k = indices[i];
indices.RemoveAt(i);
return k;
}
if(my condition is met) {
int? nextIndex = NextIndex();
lbl.Text = nextIndex == null ? "" : myString[nextIndex.Value];
}
Note that the Text is set to empty if there won't be no more remaining string, however you can handle that case yourself in another way such as keep the text unchanged.
You could probably do that, but why not get a unique list of strings first?
var uniqueStrings = myString.Distinct().ToList();
Then as you select strings, do a .Remove() on the last randomly selected value from uniqueStrings.
You said that:
I've tried using a list and removing the string I use, but it seems to repeat after all strings have been used.
The problem here is using the same instance of random for your series after you've run out. If you re-instantiate random = new Random(), the variable is re-seeded and you will have totally different results from what was generated before.

How to get the previous value in a list of strings in c#?

I'm trying to implement a previous and next buttons.
I have a list of string called list1 which is filled with whatever is a user has inputted from a textbox. I can't access the previous (not the last) string in the list. IndexOf method isn't useful as I don't know what user will input.
private void previousBtn_click(object sender, EventArgs e)
{
getList();
int min = 0;
int max = list1.Count;
if(max==min)
{
previousBtn.Visible = false;
}
else
{
int temp =list.Count-1;
//how do I get my string if I know the element index from the previous line?
//textbox1.Text = thatPreviousString;
}
}
Sorry, it should be easy but I can't figure it out. How can I actully get my previous string in the list if the value is kind of unknown to me, so I can't just use find() and indexOf.
MSDN shows that there is a property called Item but there is no proper tutorial or code bit that shows how to use it.
UPDATE:
Let's say the user has typed "www.google.com", "www.facebook.com", "twitter.com" and then "www.yahoo.com". This urls are saved in list1. The last one was "www.yahoo.com", I can get it by calling Last(). The user can press the previous button anytime, so I can't specify the number of elements in list1, it's growing dynamically. I can only get the number of elements by calling
list1.Count and the last index by calling list1[list1.Count-1]
Now I know the number of indexes and elements, so how do I get the previous string, e.g. "www.twitter.com", if I can only say I can give you the index, give my string back?
By the way, ElementAs is only for arrays, doesn't work for lists.
how do I get my string if I know the element index from the previous line?
int prevIndex; // element index from the previous line that you know
string temp = list1[prevIndex - 1];
string temp =list[list.Count-1]; will give you the last element in the list.
string temp =list[list.Count-2]; will give you the previous element.
Remember, lists are 0-indexed, ie the first element is accessed via [0], so the last element will be [list size - 1].
So in your case textbox1.Text = list[list.Count-2]; will write the previous string into the textbox.
However, that won't give you a proper previous functionality. Pressing previous again won't give you list[list.Count-3]. You could though have a currentIndex variable that you decrement whenever previous is pressed for example and do textbox1.Text = list[currentIndex].

Arrays of data classes in C#

I've been messing around with this for ages and I'm not getting any closer.
My current version is as below. The comments are what I think I'm doing.
The semantic is basically an index number (like a house number) and a list of attributes in an array. Then create an array 'street'. I want to be able to update the values of all elements in the current scope. The class is defined as high as possible so as to make the scope global. My ossified 'C' brain doesn't really understand things like lists and IEnumerable so I haven't tried to go that route. The code parser in the editor makes a bit of a mess of this - sorry.
public class house
{
// Ok, looking at this from the world of 'C' and thinking 'struct' like,
// I put my variables here.
public int my_id;
public long [] pl_id;
public house()
{
// I try to initialise the starting values, so I can carry out some tests later.
my_id = 0;
pl_id = new long[10] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
}
}
// I attempt to inform the compiler that I will be wanting an array of the house objects
// and call that array 'new_house'. Again, the code editor isn't keen.
house [] new_house;
private void button1_Click(object sender, EventArgs e)
{
// In the programs main routine (not *main*!), I then try to get the
// array 'new_house' populated with initialised 'house' objects
for (int idx = 0; idx < 10; idx++)
{
new_house[idx] = new house();
}
// And at some point in the future I wish to set or update the values arbitrarily. eg:
new_house[7].my_id = 123;
new_house[7].pl_id = 345678;
// any combination of attributes and id numbers is possible, so I use zero simply to see if they have been set, with -1 indicating failure / an absence of data-
}
}
Right. As I say, I've tried a lot of different ways to do this, and the main problem I am getting is that I never seem to correctly initialise the array 'new_house' and get null exceptions thrown when I try to assign anything. I can't believe something that seems so intuitively simple can be so hard to code, so where have I got it wrong (and I fully accept that there could be more than one conceptual or coding error in the above).
Comments on appropriateness of approach, and help with coding alike, gratefully accepted.
You need to instantiate the array before initializing items of it:
house[] new_house = new house[10];
Replace 10 with desired number of items.
In case you don't know the number, use List:
List<house> new_house = new List<house>()
Then you can dynamically add items using new_house.Add(item) and access them in foreach loop or through index new_house[i]
The first obvious problem with your code is that your constructor doesn't have the same name as the class. It should be this:
public house()
{
// ...
}
A second point is you don't need the constructor at all here:
public int my_id = 0; // The "= 0" is actually not needed here either.
public long[] pl_id = new long[10];
I would also suggest that you don't use arrays for things like houses on a street because house numbers won't necessarily be sequential. You can have gaps and even multiple houses with the "numbers" 5A and 5B. A dictionary might be a better choice.
IDictionary<string, house> houses = new Dictionary<string, house>();
If you really want to have sequential numbering you might want to consider a List<house> instead of an array so that it can be easily extended if new houses are built.
Finally I'd advise using PascalCase for classes. It will make your code much easier to read if you use the same standards as the rest of the .NET framework.
Change public game()
to public house()
Your constructor has to have the same name as the class.
A couple things:
new_house is never initialized. You can't use it until you've initialized it.
pl_id is an array, but you attempt to store a long in it (345678) -- you could change it to new int[] { 345678}.
You've got a method, game(), in the class house which looks and acts like a constructor. You would have to name it house() if it is meant to be a constructor.
not public game()
right: public house()
Always the constructor has to have the same name as the class.
Use List<T> for those collections. Try not to say you don't understand something because you are 'c' addicted. Try to say yourself you want to try something new and search for a good solution
namespace Myprog
{
// I attempt to inform the compiler that I will be wanting an array of the house objects
// and call that array 'new_house'
List<house> houselist = new List<house>();
private void button1_Click(object sender, EventArgs e)
{
// In the programs main routine (not *main*!), I then try to get the
// array 'new_house' populated with initialised 'house' objects
for (int idx = 0; idx < 10; idx++)
{
houselist.add(new house());
}
// And at some point in the future I wish to set or update the values arbitrarily. eg:
houselist[7].my_id = 123;
// any combination of attributes and id numbers is possible, so I use zero simply to see if they have been set, with -1 indicating failure / an absence of data-
}
}
}

Categories

Resources