How to have n variables in C# - c#

imagine this code
for (int iDay = 1; iDay <= total_days; iDay++)
{
question = CheckString(s.challenge_1_q);
answer = CheckStringA(s.challenge_1_a);
// more here
}
but what I really have is from challenge_1_q to challenge_24_q and challenge_1_a to challenge_24_a
what is my best option to have dynamic variables as today it's 24, "tomorrow" could be only 18.
is the use of dynamic the proper way? or I really need to have a switch and forget about dynamism ?

Create a class called QuestionAnswer, then store a List on s.
The accessing code will look like this:
question = CheckString(s.QuestionAnswers[i].Question);
answer = CheckStringA(s.QuestionAnswers[i].Answer);
The QuestionAnswer class:
public class QuestionAnswer
{
public string Question{get; set;}
public string Answer{get; set;}
}
And the definition on your existing class:
public List<QuestionAnswer> QuestionAnswers = new List<QuestionAnswer>();
Instead of having dozens of variables, you add dozens of items to the list:
QuestionAnswer qa = new QuestionAnswer();
qa.Question = "What letter comes after A?";
qa.Answer = "B";
QuestionAnswers.Add(qa);
//repeat for all your questions.

You can also create Structure
struct QuestionBank
{
public string Question;
public string Answer;
}
And use Something like this
QuestionBank []Quiz = new QuestionBank[n]; //n is number of question and answers
Quiz[0].Question = "SomeQuestion";
Quiz[0].Answer = "SomeAnswer";
Quiz[1].Question = "SomeAnotherQuestion";
Quiz[1].Answer = "AnswerAsWell";
.....
Quiz[n].Question = "nth Question";
Quiz[n].Answer = "nth AnswerAsWell";

Related

C# - dictionary - How to get max of specific class value in dictionary? [duplicate]

This question already has answers here:
How to get MAX value from Dictionary?
(8 answers)
Closed 2 years ago.
I have a dictionary where I'm trying to find the max of a specific class value, similar to getting max of a list. I've been searching for a couple of hours but all I'm finding is how to grab a value from a dictionary that has a key and a single value. I've also come across Linq but I'm not finding anything on how to search a dictionary's class values for the Max value. I'm pretty sure there is a way and I'm just missing something?
In my case, I'm trying to find the Max lineDistance of my class LineInfo
Links that I have found are close
this one but it only deals with a single key and a single value, not a class
this one seems like it might be on the right track but the checked answer suggests to run a nested foreach. I would imagine there's an easier / more sosphisticated way?
Any and all help is appreciated.
here is my code, it's fairly simple:
class LineInfo
{
public double lineDistance { get; set; }
public LineSegment2d lineSegment2D1 { get; set; }
public LineSegment2d lineSegment2D2 { get; set; }
}
var lines = new Dictionary<int, LineInfo>();
double pointDistance0 = lineSegment2DList[i].StartPoint.GetDistanceTo(lineSegment2DList[j].StartPoint);
lines.Add(0, new LineInfo {lineDistance = pointDistance0, lineSegment2D1 = lineSegment2DList[i], lineSegment2D2 = lineSegment2DList[j] });
double pointDistance1 = lineSegment2DList[i].StartPoint.GetDistanceTo(lineSegment2DList[j].EndPoint);
lines.Add(1, new LineInfo { lineDistance = pointDistance1, lineSegment2D1 = lineSegment2DList[i], lineSegment2D2 = lineSegment2DList[j] });
double pointDistance2 = lineSegment2DList[i].EndPoint.GetDistanceTo(lineSegment2DList[j].StartPoint);
lines.Add(2, new LineInfo { lineDistance = pointDistance2, lineSegment2D1 = lineSegment2DList[i], lineSegment2D2 = lineSegment2DList[j] });
double pointDistance3 = lineSegment2DList[i].EndPoint.GetDistanceTo(lineSegment2DList[j].EndPoint);
lines.Add(3, new LineInfo { lineDistance = pointDistance3, lineSegment2D1 = lineSegment2DList[i], lineSegment2D2 = lineSegment2DList[j] });
To get LineInfo with maximum lineDistance you can use Values collection. Since there is no MaxBy in standard LINQ you can achieve similar effect with Aggregate:
var max = lines.Values
.Aggregate((acc, curr) => acc.lineDistance > curr.lineDistance ? acc: curr);
If I'm understanding the question correctly, there's an overload for Max in Linq which allows you to specify a property, i.e:
double max = lines.Max(x => x.Value.lineDistance);
Edit
If you're wanting the object, than #itsme86 solution works the best:
LineInfo maxLineInfo = lines.Values.OrderByDescending(line => line.lineDistance).First();

Setting the size of an array using input from textbox in win forms

I am trying to use the input given in Form1 to define the size of the array but am getting an error saying that a field initializer cannot use a non-static field. This always worked for me in CLI but for some reason it is not working here.
namespace Class_Grade_Register
{
public partial class Student_Input : Form
{
int number_Of_Students = 0;
int counter = 0;
string[] studentName = new string[number_Of_Students];
int[] sfcGrade = new int[number_Of_Students]; // this is where I am getting the error. number_Of_Students is being underlined in red.
int[] csGrade = new int[number_Of_Students];
int[] sdtGrade = new int[number_Of_Students];
int[] ddoocpGrade = new int[number_Of_Students];
public Student_Input()
{
InitializeComponent();
}
public void Set_Number_Of_Students(int value)
{
number_Of_Students = value;
}
The idiomatic way of representing complex data (basically, anything where you have to connect two integers or strings together somehow) is by creating classes. Beginners are strangely reluctant to do this, instead creating arrays or multiple variables like student1Name, student2Name and so on.
Don't be like that, classes are a fundamental concept in object-oriented programming and you have got to become comfortable with them. Start with something like this:
public class Student
{
public string Name { get; }
public int Grade { get; }
public Student(string name, int grade)
{
Name = name ?? throw new ArgumentNullException(nameof(name));
Grade = (grade > 0) ? grade : throw new ArgumentException(nameof(grade));
}
}
Add new properties as you need them. Also get in the habit of throwing exceptions when you detect something is wrong. Beginners have a bad habit of trying to hide exceptions. Doing that puts errors in your data and prevents you from finding them.
Now you can start creating students:
var me = new Student("Dour High Arch", 10);
If you want to create a bunch of students, use a list or collection:
var students = new List<Student>().
students.Add(me);
You have another bad design in your code; asking for the total number of students before adding them. This causes problems like null references if not as many students get added as your total number, or out-of-range exceptions if more students get added than your total number. Moreover in many real-world situations you won't know how many students or whatever there are until you've added them all. Use a design more like this:
while (true)
{
var nextStudent = GetStudentFromSomewhere();
if (nextStudent == null)
break;
students.Add(nextStudent);
}
Arrays are designed for collections which must always contain a set number of elements and cannot change, like the months of a year. If you expect the number of elements to change you should not use an array.
try making number_Of_Students static, something like this:
static int number_Of_Students = 0;
and also you need to modify your Set_Number_Of_Students method to something like this:
public void Set_Number_Of_Students(int value)
{
number_Of_Students = value;
studentName = new string[number_Of_Students];
sfcGrade = new int[number_Of_Students];
csGrade = new int[number_Of_Students];
sdtGrade = new int[number_Of_Students];
ddoocpGrade = new int[number_Of_Students];
}
int number_of_students = 0;
int[] sfcGrade;
public void Set_Number_of_Students(int value)
{
number_of_students = value;
sfcGrade = new int[number_of_students];
}
As described here the compiler will not necessarily initialize number_of_students before sfcGrade leading to the index size of sfcGrade being an undefined int.

Use string variable to identify corresponding instance of a class

I have a simple class to define rooms. Initially I set up all the rooms I need, (Could be hundreds in a long list), though in my example I set up just 3. Then I have a string that I will use to reference the right instance of Rooms class. For instance, this could be "X10Y10". I want to use that string to identify the corresponding Rooms instance, but don't know how to associate them.
void Start () {
Rooms X10Y10 = new Rooms();
X10Y10.Name = "The Great Room";
X10Y10.RoomMonsters = 10;
X10Y10.Ref = "001";
Rooms X11Y10 = new Rooms();
X11Y10.Name = "Smoking room";
X11Y10.RoomMonsters = 2;
X11Y10.Ref = "002";
Rooms X12Y10 = new Rooms();
X12Y10.Name = "Hunting Room";
X12Y10.RoomMonsters = 7;
X12Y10.Ref = "003";
// Don't Know the room Ref until runtime, during game.
// Want to get the room instance properties of one of the rooms eg.
string RoomAtRuntime = "X11Y10"; // dont know this until game is running
// fix following lines
print(RoomAtRuntime.RoomMonster); // would return 2
print(RoomAtRuntime.Name); // would return Smoking room
}
public class Rooms
{
public string Ref { get; set; }
public string Name { get; set; }
public int RoomMonsters { get; set; }
}
It sounds like what you need here is a Dictionary - a collection which associates Keys with Values. In your case, you can associate each string key with a different Rooms instance, making it easy (and efficient) to quickly access any instance. Here's what your code might look like with this change:
// Declare and initialize dictionary before using it
private Dictionary<string, Rooms> roomCollection = new Dictionary<string, Rooms>();
void Start () {
// After you instantiate each room, add it to the dictionary with the corresponding key
Rooms X10Y10 = new Rooms();
X10Y10.Name = "The Great Room";
X10Y10.RoomMonsters = 10;
X10Y10.Ref = "001";
roomCollection.Add("X10Y10", X10Y10);
Rooms X11Y10 = new Rooms();
X11Y10.Name = "Smoking room";
X11Y10.RoomMonsters = 2;
X11Y10.Ref = "002";
roomCollection.Add("X11Y10", X11Y10);
Rooms X12Y10 = new Rooms();
X12Y10.Name = "Hunting Room";
X12Y10.RoomMonsters = 7;
X12Y10.Ref = "003";
roomCollection.Add("X12Y10", X12Y10);
// The rooms should now all be stored in the dictionary as key-value pairs
string RoomAtRuntime = "X11Y10";
// Now we can access any room by its given string key
print(roomCollection[RoomAtRuntime].RoomMonster);
print(roomCollection[RoomAtRuntime].Name);
}
Note that you may need to add the directive using System.Collections.Generic to your script file.
You can (and probably should) also use something other than a string for your key value. Here, I think it'd make more sense to use a Vector2 value for these X/Y coordinates, rather than strings. (So, something like roomCollection.Add(new Vector2(10, 10), X10Y10); would be more appropriate.)
Hope this helps! Let me know if you have any questions.

Using variable in the name

Is it possible to use a variable to access 2 variables without naming another variable?
For example, to:
LOG.dig.CNLog = 7;
LOG.value.CNLog = 17;
I would like to use something like this
string a = "dig";
string b = "value";
LOG.[a].CNLog = 7;
LOG.[b].CNLog = 17;
It's possible to use this? If yes what is the correct format?
Thanks
You can use a Dictionary<string, int>. An example:
var dict = new Dictionary<string, int>();
dict.Add("test", 1);
var testVal = dict["test"];
You can do that by using a Dictionary<TKey, TValue>.
A dictionary is a collection of keys and values. In your case you probably would like to use a Dictionary<string, LogClass> then you can have something like this:
Assuming LogClass is your class...
public class LogClass
{
public int CNLog { get; set; }
}
string a = "dig";
string b = "value";
dictionary[a].CNLog = 7;
dictionary[b].CNLog = 17;
But of course before doing that you would have to say what is the value that goes into dictionary[var].
dictionary[a] = new LogClass();
That is how you would use it, hopefully you will be able to adapt this solution to your code.
And you can check out a video that explains step-by-step very slowly and clearly how to work with it on Microsoft Virtual Academy: C# Fundamentas at 22:00.

C# Array Conversion

Any help here as I'm a C# noob. The following code works fine and returns 1 string ViewState2. I'd like it to return an array of ViewState2 and EventValidation2 so I can manipulate it later on. How would I convert the code below to return an array?
public string get_status(string local_fname)
{
var dts_doc = new HtmlAgilityPack.HtmlDocument();
dts_doc.Load(local_fname);
//Pull the values
var ViewState = dts_doc.DocumentNode.SelectSingleNode("/html[1]/body[1]/div[1]/input[4]/#value[1]");
var EventValidation = dts_doc.DocumentNode.SelectSingleNode("/html[1]/body[1]/div[2]/input[1]/#value[1]");
string ViewState2 = ViewState.Attributes[3].Value;
string EventValidation2 = EventValidation.Attributes[3].Value;
//Display the values
//System.Console.WriteLine(ViewState.Attributes[3].Value);
//System.Console.WriteLine(EventValidation.Attributes[3].Value);
//System.Console.ReadKey();
return ViewState2;
}
Don't use an array, but a class. Doing this, you don't have to remember what each element means.
public class Status
{
public string ViewState {get; set;}
public string EventValidation {get; set;}
}
using System;
using HtmlAgilityPack;
[...]
public Status GetStatus(string localFileName)
{
var dtsDoc = new HtmlDocument();
dtsDoc.Load(localFileName);
//Pull the values
var viewStateNode = dtsDoc.DocumentNode.SelectSingleNode("/html[1]/body[1]/div[1]/input[4]/#value[1]");
var eventValidationNode = dtsDoc.DocumentNode.SelectSingleNode("/html[1]/body[1]/div[2]/input[1]/#value[1]");
string viewState = viewStateNode.Attributes[3].Value;
string eventValidation = eventValidationNode.Attributes[3].Value;
//Display the values
//Console.WriteLine(viewState);
//Console.WriteLine(eventValidation);
//Console.ReadKey();
return new Status
{
ViewState = viewState,
EventValidation = eventValidation
}
}
Also, you should read up on coding guidelines and naming conventions in the C# language, also the using statement might be interesting. I have corrected some "mistakes", but probably didn't catch all. Also, I have renamed a couple of variables, to make their content clearer. You also might want to look into using the var keyword only in a loop, while using LINQ (or anomynous types in general) or with really long class names. Written out type names can increase readability quite a lot.
If you really want an array with ViewState2 and EventValidation2 in it, you can make the following changes:
// Notice: return value of string[] instead of string
public string[] get_status(string local_frame);
And:
// Notice: returning an array
return new string[] { ViewState2, EventValidation2 };
That said, this is really the "quick and dirty" approach, and is not really appropriate if you're going to want this code to be maintainable (when's the last time you read documentation on a function that "returns an array of length 2, with a string representing X as the first element and another string representing Y as the second"?).
Femaref's right; the correct thing to do would be to encapsulate the information you want returned in its own type.
Assuming you answer yes to this question (although I'd recommend a different approach, see below) this will do what you're asking:
public String[] get_status(string local_fname)
{
var dts_doc = new HtmlAgilityPack.HtmlDocument();
dts_doc.Load(local_fname);
//Pull the values
var ViewState = dts_doc.DocumentNode.SelectSingleNode("/html[1]/body[1]/div[1]/input[4]/#value[1]");
var EventValidation = dts_doc.DocumentNode.SelectSingleNode("/html[1]/body[1]/div[2]/input[1]/#value[1]");
string ViewState2 = ViewState.Attributes[3].Value;
string EventValidation2 = EventValidation.Attributes[3].Value;
String[] retValues = new String[2];
retValues[0] = ViewState2;
retValues[1] = EventValidation2;
return retValues;
//Display the values
//System.Console.WriteLine(ViewState.Attributes[3].Value);
//System.Console.WriteLine(EventValidation.Attributes[3].Value);
//System.Console.ReadKey();
return ViewState2;
}
That said, I would follow the approach afte the line.
I'd write a class that has the data members you want:
public class DataClass
{
public string ViewState { get; set; }
public string EventValidation { get; set; }
}
Then I'd modify the method to return an instance of your data class.
public DataClass get_status(string local_fname)
{
var dts_doc = new HtmlAgilityPack.HtmlDocument();
dts_doc.Load(local_fname);
//Pull the values
var ViewState = dts_doc.DocumentNode.SelectSingleNode("/html[1]/body[1]/div[1]/input[4]/#value[1]");
var EventValidation = dts_doc.DocumentNode.SelectSingleNode("/html[1]/body[1]/div[2]/input[1]/#value[1]");
var dc = new DataClass();
dc.ViewState = ViewState.Attributes[3].Value;
dc.EventValidation = EventValidation.Attributes[3].Value;
return dc;
}
string[] array = new string[2];
array[0] = ViewState2;
array[1] = EventValidation2;
return array;
But it seems to trivial as answer. Please Does it solve your problem? If no, can you specify better the question please?

Categories