I have this loop here, which for each question it is supposed to create, it generates and then formats a 'worded question' from an array of questions, such as; 'What is the sum of {0} + {1}?'. This loop then formats it, adds the worded question and the answer to an array.
// Use for loop to create the correct amount of questions
for (int i = 0; i < Data.Questions.numQuestions; i++)
{
Random rnd = new Random();
Data.Questions.Sum sum = new Data.Questions.Sum();
// Create part one and part two of the question using random numbers
// ex. 3 + 5
// 3 = partOne, 5 = partTwo
int partOne = rnd.Next(Data.Questions.Sum.min, Data.Questions.Sum.max);
int partTwo = rnd.Next(Data.Questions.Sum.min, Data.Questions.Sum.max);
// Randomly select one of the word questions
string fullQuestion = Data.Questions.Sum.wordedQuestions[rnd.Next(0, Data.Questions.Sum.wordedQuestions.Length)];
// Format the string with the generated numbers
fullQuestion = string.Format(fullQuestion, partOne, partTwo);
// Set out-of-class variables to be displayed to the user
Data.Questions.Sum.questions[i] = fullQuestion;
Data.Questions.Sum.answers[i] = partOne + partTwo;
}
Both Data.Questions.Sum.questions and Data.Questions.Sum.answers are List<string>'s and List<int>'s.
However, when this loop is run, with i = 0, I am thrown;
System.ArgumentOutOfRangeException: 'Index was out of range. Must be
non-negative and less than the size of the collection. Parameter name:
index'
Does anyone know what I'm doing wrong? As far as I know lists are dynamic, and I've defined like this;
// Arrays containing all questions and answers
// used to display questions and check answers
public static List<string> questions = new List<string>();
public static List<int> answers = new List<int>();
Also, to clarify, I do not want to use .Add(), as I have a settings panel which when you hit apply, re-runs this loop so the questions are up to date to the current settings. I need the loop to override the previous values.
Edit:
When using arrays, the better option here, I get;
System.IndexOutOfRangeException: 'Index was outside the bounds of the array.'
On assigning Data.Questions.Sum.answers[i], after assigning the array like so; public static int[] answers {};
If you can't .Add() in this lists - create a copy of this lists and .Add() there. Lists has special for that kind of thing: new List<T>(IEnumerable<T>)
If you need to dynamically scale the collection, but you also need to iterate over it multiple times, then you'll need to check whether it is large enough to either insert, or just update.
You can do this with an extension method such as this...
public static class ListExtentions
{
public static void AddOrUpdate<T>(this List<T> that, int index, T value)
{
if (that.Count > index)
{
that[index] = value;
}
else
{
that.Add(value);
}
}
}
...which can then be called like this...
list.AddOrUpdate(index, value);
...however you can make things easier for yourself if you know how many questions you are going to have to start with.
If the number of questions changes when your UI changes, then you will also have to deal with the issue have scaling down the collection to ensure old elements are removed, which is much simpler if you just re-instantiate the collections every time you need to regenerate the questions / answers.
This is likly to be cause of your problem,(I have asked for clarification in comments where you didn't reply).
Still putting this as an answer, as it is potential error spot and you need to fix this.
As you mentioned you are facing this exception on i=0. there are high chanced that this is every time case not any specific case.
If Data.Questions.Sum.questions is empty then, Data.Questions.Sum.questions[i] = fullQuestion; , will surely throw such exception. Same way for Data.Questions.Sum.answers too.
In such case, you must use .Add() to insert into list.
so your code should be,
if (Data.Questions.Sum.questions.Count > i)
Data.Questions.Sum.questions[i] = fullQuestion;
else
Data.Questions.Sum.questions.Add(fullQuestion);
But if they are not empty, it must not be the cause of this exception.
One more thing i have noticed in your code is Data.Questions.Sum.wordedQuestions.
Even if you have valid list (here Data.Questions.Sum.wordedQuestions) - as you have Length prop, it must be Array not list.
If it is empty, while doing this
string fullQuestion = Data.Questions.Sum.wordedQuestions[rnd.Next(0, Data.Questions.Sum.wordedQuestions.Length)];
this line will surely throw
An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll
as you are trying to get 0th index's data from it.
So before fetching data from list or array, first you need to check if it does have data init, and also it does have that index which you are asking.
something like
string fullQuestion = string.Empty;
if (Data.Questions.Sum.wordedQuestions != null &&
Data.Questions.Sum.wordedQuestions.Length > 0)
{
//here the way you are creating random number,
// you are assured about index is present in array.
int indexForWordedQuestion = rnd.Next(0, Data.Questions.Sum.wordedQuestions.Length);
fullQuestion = Data.Questions.Sum.wordedQuestions[indexForWordedQuestion];
}
Related
I have a simple form that accepts a number from a radio button selection (1-5) of 11 questions and posts the values into a database as varchar(10) data. I intend to send the user to a result page that lists the sum of these scores through a simple for loop, but when I try parsing the data to integer format, it simply results in zero due to error parsing. Here's an example of my code:
// Q1 - Q11 are the questions in my Db, using Model property
int sum = 0;
int temp = 0;
String question;
for (int i = 11; i >= 1; i--)
{
question = "Model.Q" + i.ToString();
temp = int.Parse(question);
sum += temp;
}
return sum;
What's strange is that if I parse them individually, such as writing:
Int32.TryParse(Model.Q5, out temp);
I am able to parse the data just fine. My console shows that the loop keeps the question variable as "Model.Qx" with quotations, ultimately resulting in 0 for the sum. I have also tried using Int32.TryParse(); for that as well and it resulted in no difference, besides handling the error.
Can a string simply not be parsed if it contains punctuation in concatenation with the i variable, or am I missing something else here? I want to avoid parsing each question individually, as it looks rather ugly in code.
Thanks in advance.
You problem is that you're trying to access a variable by using a string with the same name. This won't work, in the same way that the name gitgecko is not you.
If your model has got a number of properties with similar names, you could write a function to switch between them:
object GetQ(int number)
{
switch(number)
{
case 1: return Model.Q1;
case 2: return Model.Q2;
// etc...
}
}
Or you could change your model to store these variables in an array or list, or whatever is appropriate.
For example, if you've currently got:
class Model
{
string Q1;
string Q2:
// repeated 11 times
You could have:
class Model
{
string[] Q = new string[11];
}
which gives you the ability to do Model.Q[x]
I'm currently taking a intermediate course on Udemy for C# and I'm trying to do one of the exercises. I've looked in the Q&A for students to see other peoples solutions, I've even copied and pasted other peoples solutions to see if theirs works and they do, I don't see any difference between mine and other peoples but for some reason my code prints out the numbers from highest to lowest and no where in the code should this happen. The idea of the exercise was to create a stack, we have 3 methods: Push(), Pop(), and Clear(). The push method adds objects to an ArrayList, the pop method removes the number from the top of the stack and returns the number. The clear method is self explanatory. Here's my code:
Stack Class:
public class Stack {
private ArrayList _arrayList = new ArrayList();
public void Push(object obj) {
if (obj is null) {
throw new InvalidOperationException();
}
else {
_arrayList.Add(obj);
}
}
public object Pop() {
if (_arrayList is null) {
throw new InvalidOperationException();
}
else {
var top = _arrayList.Count;
_arrayList.Remove(top);
return top;
}
}
public void Clear() {
for (int i = 0; i < _arrayList.Count; i++) {
_arrayList.Remove(i);
}
}
}
Program Class:
class Program {
static void Main(string[] args) {
var stack = new Stack();
stack.Push(5);
stack.Push(1);
stack.Push(2);
stack.Push(4);
stack.Push(3);
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
}
}
var top = _arrayList.Count;
_arrayList.Remove(top);
return top;
You aren't printing the values, you're printing the number of elements stored.
Try changing your values to be something other than the first few positive integers to catch this kind of mistake more easily.
PS: There's been no reason to use ArrayList for over a decade. The generic collection classes such as List<int> are better in every way -- faster, less wasted memory, type safety.
var top = _arrayList.Count;
_arrayList.Remove(top);
return top;
top is assigned the value of the size of the list, and is never reassigned. Thus it looks like it prints highest to lowest because its just printing the size of the stack (which of course is 5, then 4, then 3, and so on). It only looks like you printed the contents of your list because you happened to push the same numbers. Some different test data would have made this bug more obvious.
I think what you actually wanted was
var top = _arrayList[_arrayList.Count -1];
Note that your code would fail miserably if there was a duplicate element in the list (due to removing based on the item value and not on the index). You also really shouldn't be using ArrayList at all; that's a .NET 1.0 class that's just an awful collection interface. Use a generic like List<T>.
You are returning
var top = _arrayList.Count;
Not the value in that position.
_arrayList(top-1);
You should be getting an index out of range error on that remove.
_arrayList.Remove(top);
I am just beginning with programming in c#;
I got a list of int variables that I want to sort, and find the number 1.
int Weapon_Count1, Weapon_Count2, Weapon_Count3, Weapon_Count4, Weapon_Count5, Weapon_Count6, Weapon_Count7, Weapon_Count8, Weapon_Count9
do I need to do this with an array?
By using the yellow book of C# I found out how to make an array, but I can't figure out how to assign the variables to the array.
int [] Weapon_Count = new int [11] ;
for ( int i=0; i<11; i=i+1)
{
Weapon_Count [i] = ??? ;}
I hope this does make sense..
Please let me explain how to use a C#-array.
This creates an unitialized integer-array with 5 elements:
int[] a1= new int[5];
Assigning values 9,8,7,6 and 5:
(Please note that only indexes from 0 to 4 can be used. Index 5 is not valid.)
a1[0]=9;
a1[1]=8;
a1[2]=7;
a1[3]=6;
a1[4]=5;
The same can also achieved with just one line:
int[] a1= new int[] {9,8,7,6,5};
This might help you.
// Declaring the array
int[] Weapon_Count;
// Initializing the array with a size of 11
Weapon_Count = new int[11];
// Adding values to the array
for (int i = 0; i < Weapon_Count.Length; i++)
{
Weapon_Count[i] = i + 100;
}
// Printing the values in the array
for (int i = 0; i < Weapon_Count.Length; i++)
{
Console.WriteLine(Weapon_Count[i]);
}
// Same thing with a list
// Daclare and initializing the List of integers
List<int> weapon_list = new List<int>();
// Adding some values
weapon_list.Add(1);
weapon_list.Add(2);
weapon_list.Add(3);
weapon_list.Add(4);
weapon_list.Add(5);
// Printing weapin_list's values
for (int i = 0; i < weapon_list.Count; i++)
{
Console.WriteLine(weapon_list[i]);
}
// This is just for the console to wait when you are in debug mode.
Console.ReadKey();
Dont forget to include the using statment if you want to use lists (in short hand - dynamic arrays that can change in size.)
using System.Collections.Generic;
The easiest way to do this, assuming there is a finite list of variables to check, would be to throw them into a temporary array and call either Max() or Min() from the System.Linq namespace.
int maxCount = new int[] { Weapon_Count1, Weapon_Count2, Weapon_Count3, Weapon_Count4, Weapon_Count5, Weapon_Count6, Weapon_Count7, Weapon_Count8, Weapon_Count9 }.Max(); // or .Min()
EDIT
If you still want to get those variables into an array, I would recommend using a System.Collections.Generic.List which has a dynamic size and helper methods such as .Add() to simplify things. Lists can also be used with Linq functions similar to the first part of my answer. See Dot Net Perls for some really good examples on different C# data types and functions.
EDIT 2
As #kblok says, you'll want to add using System.Linq; at the top of your file to gain access to the functions such as Max and Min. If you want to try using the List type, you'll need to add using System.Collections.Generic; as well. If you're in Visual Studio 2017 (maybe 2015 as well?) you can type out the data type and then hit Ctrl + . to get suggestions for namespaces that might contain that data type.
Before we start, you might edit your array to look like this:
int[] weapons = { Weapon_Count1, Weapon_Count2, Weapon_Count3, Weapon_Count4, Weapon_Count5, Weapon_Count6, Weapon_Count7, Weapon_Count8, Weapon_Count9 };
This means that you've created an array called weapons and it is holding integer values.
After you did this, lets find out which element in your array has value of number one.
To find which value has value "1" we must look at each element in array, and we might do that on few ways but I would like recommend foreach or for loop, in this case I will choose foreach loop.
foreach(var item in weapons)
{
if (item == 1)
//Do something
}
This above means, loop throught all of my elements, and in case some of them is equal to number one please do something..
P.S
(I may advice to create one variable which will hold an element which has value '1' and when you find it in a loop assing that variable to that element, and later you can do whatever you want with that variable.. and if you think there will be more elements with value of number one and you need all of them, instead of variable I mentioned above you will create list or array to hold all of your elements and also you can do later with them whatever you want to.)
Thanks and if you are interested in this kind of solution, leave me a comment so let me help you till the end to solve this if you are still struggling.
I am creating static class using a static method that is comparing a string filled with selections from a user input, and a predefined array of what is "supposed to be the inputs";
My concern is the placement of the pre-defined array within the class and if the correct data type to be used is actually an array or a dictionary.
I will have roughly 150 strings max in the pre-defined and ready to compare against string array.
here is what I have so far.
public static class SelectionMatchHelper
{
static readonly string[] predefinedStrings = {"No answer", "Black", "Blonde"};
public readonly static bool SelectionMatch(string[] stringsWeAreComparingAgainst, int validCount)
{
int numberOfMatches = 0;
for (int x = 0; x < "length of string array"; x++)
{
//will loop through and check if the value exists because the array to match against will not always have the same index length
numberOfMatches += 1;
}
numberOfMatches.Dump();
if (numberOfMatches == 0 || numberOfMatches < validCount || numberOfMatches > validCount) return false;
return true;
}
}
what this basically does, is based on the number of parameters the user must fulfill, the method gets the matches, if it doesn't equal that amount then it returns false. The input the user is using is a drop down, so this is only being used to make sure my values aren't tampered with prior to saving.
My question is what data type is best used for this scenario an string array/list or dictionary? The second question is where should that be placed in order to avoid a thread issue, inside the method or out?
EDIT - I just want to add that the pre-defined values would remain the same, so I would end up making that field a readonly const value.
EDIT 2 - Just re-checked my code I wont be using CompareOrdinal because I totally forgot the part where the order matters. So it will be a key look up. So I will remove the inside of the method so people don't confused. The main question is still the same.
Thanks for your help everyone.
From readability point of view HashSet is the best type as it specifically exists for "item is present in the set".
static readonly HashSet<string> predefinedStrings = new HashSet<string>(
new []{"No answer", "Black", "Blonde"},
StringComparer.Ordinal);
if (predefinedStrings.Contains("bob"))....
Fortunately HashSet also thread safe for read-only operations, provides O(1) check time and supports case insensitive comparison if you need one.
This question already has answers here:
Directly modifying List<T> elements
(6 answers)
Closed 8 years ago.
I am writing a function which is passed in a list which is partially filled. I'd like to set some of the fields within the list inside this function. I thought that passing it as a reference would allow me to do this, however, I get the following error:
Error 1 Cannot modify the return value of 'System.Collections.Generic.List.this[int]' because it is not a variable
I am wondering what I might need to do to tell C# that I wish to have the option of modifying the contents of the list.
Here is a summarized version of my code:
public static void Determine_RTMM_Descriptor(ref List<Struct_Descriptor_Type> symbols, string Dwarf_Output_Filename)
{
...
lines = System.IO.File.ReadAllLines(Dwarf_Output_Filename);
//loop on symbol names
for (int idx = 0; idx < symbols.Count; idx++)
{
if(symbols[idx].size == 0)
symbols[idx].size = (int)new System.ComponentModel.Int32Converter().ConvertFromString(split_line[DwarfInterface.SIZE_INDEX]);
...
}
Thanks in advance for any help.
The underlying issue here is that you have a list of value types. When you use the indexer of the list to get an item from the list you are getting a copy of that type. The code symbols[idx] is the value of that item. It is not a variable representing that item, as the error message is telling you.
You're trying to mutate the size of the copy, which will have no effect on the item of the list. This is such a common mistake that the compiler even makes this an error.
If you really are sure that you want to have a mutable value type (hint: you aren't, and you shouldn't have one; you almost certainly just want to have a class here to avoid this problem entirely) then you would need to get the value of the item, mutate it, and then set the item again:
if(symbols[idx].size == 0)
{
var symbol = symbols[idx];
symbol.size = 42;
symbols[idx] = symbol;
}
Your return type on the function is "void" when you should set the return type to the list. That should allow you to change it and return it modified.