How to store the string with function in C# - c#

I'm beginner in C# programming. I'm struck with this simple program where I want to display the eligible candidates. My question is that how can I store the name of candidate after knowing that he/she is eligible.
int eligble = 0; //For counting the eligble Number of candidates
bool retry; //For trying until the Number of eligble candidates is reached
retry = true;
while (retry)
{
string candidatename; //Intilization for Candidate Name ,Date of Birth ,10th and 12th Percentages
int tper, twper;
string dob;
Console.WriteLine("Please enter your Name"); //Getting user input values
candidatename = Console.ReadLine();
Console.WriteLine("Please enter your date of birth in dd/mm/yyyy format");
dob = Console.ReadLine();
DateTime dt = Convert.ToDateTime(dob);
Console.WriteLine("Please enter your 12th percentange");
twper = Convert.ToInt16(Console.ReadLine());
Console.WriteLine("Please enter your 10th percentange");
tper = Convert.ToInt16(Console.ReadLine());
int age1 = age(dt);
if (eligble > 5) //Checking whether we have selected the Eligble amount of candidates
{
Console.WriteLine("We have selected five eligble candidtes");
retry = false;
Console.WriteLine("n");
}
else
{
if (age1 > 20 && twper > 65 && tper > 60) //Checking Whether the candidate have satisfiyed the Conditions
{
eligble += 1;
string grad = rade(twper, tper);
}
else
{
eligble -= 1;
}
}
}
}
static int age(DateTime _dt) //Function for calculating the age of the candidate
{
DateTime n = DateTime.Now; // To avoid a race condition around midnight
int age = n.Year - _dt.Year;
if (n.Month < _dt.Month || (n.Month == _dt.Month && n.Day < _dt.Day))
age--;
return age;
}
static string rade(int _tper, int _twper)
{
string grade1;
int avg= ( _tper+_twper)/ 2;
if (avg > 90)
{
grade1 = "a";
return grade1;
}
else if (avg > 80 && avg < 80)
{
grade1 = "b";
return grade1;
}
else if (avg > 70 && avg < 79)
{
grade1 = "c";
return grade1;
}
else
{
grade1 ="d";
return grade1;
}
}

"Store" has broad meaning. You can store your data in memory for the time your program is running. In that case C# offers plenty of collections. List will work if you just want to keep them.
var names = new List<string>();
names.Add(candidate.Name);
If you prefer to store them with some kind of a key and then use the key to get the value from the collection better choice would be a dictionary:
var myEligibleCandidates = new Dictionary<string, string>();
myEligibleCandidates[candidate.Id] = candidate.Name;
These option will preserve the values for the time the application is running.
If you want your values to be stored also after the program is not running you can do that using a file. A static File class can be a good start:
public void WriteToFile(string path, List<string> names)
{
File.WriteAllText(path, string.Join(";", names));
}
This method will take a list of names as a parameter and will write them separated by semicolon to a file. path is the path of the file.
Then there is option to save your data in the database. If that's what you want to do then take a look at Entity Framework and ADO.NET. Though, I would wait with these two options till you get better understanding of the first and second solution.

make a new List object, to do so do:
List<string> eligableCandidates = new List<string>();
and then when you want to add something to the list do:
eligableCandidates.Add(candidateName);
Hope this helps,
Jason.

Related

How can I stop my average output from displaying the same letter grade as my original grade output? Also how to make sentinel values case insensitve?

I have a program that is supposed to return your grades and grade average to you using a sentinel value to end the program, while also using input validation. The issue that I am having at the moment is that it runs greatly and it stops when I use "Quit", but my ending prompt of:
Console.WriteLine("The average is {0} is a(n) {1}", average, grade);
is returning me the same letter grade as the prompt for my:
Console.WriteLine("A grade of {0} is a(n) {1}", anInt, grade);
I also need to make the quit be case insensitive so I tried to use the .ToLower() method, my program would not run properly and I would get an error that says "error CS0019: Operator ==' cannot be applied to operands of type method group' and `string'".
My code is listed below and I was wondering if the issue is that I am using the same string function to return both letters and that is why they are mimicking one another? For example, if I enter a grade that is returned as an F as the last letter in the program, the average grade will show as an F at the end of the program regardless of what the numerical grade value that represents the average is. I was also wondering if there was a proper way to implement the .ToLower() method, because I have tried it a few times and it kept giving me errors, so I just removed it as a whole.
using System;
class Program {
public static void Main (string[] args) {
int sum=0;
int count = 0;
string grade = "A";
bool KeepGoing = true;
while (KeepGoing){
string entry = GetEntry();
if (entry == "Quit") {
KeepGoing = false;
} else {
int anInt = Convert.ToInt32(entry);
grade = DetermineGrade(anInt);
sum += anInt;
count++;
Console.WriteLine("A grade of {0} is a(n) {1}", anInt, grade);
}
}
double average = sum/ (double)count;
Console.WriteLine("The average is {0} is a(n) {1}", average, grade);
}
public static string DetermineGrade(int anInt) {
if (anInt >= 90){
return "A";
}
if (anInt >= 80 & anInt <= 89){
return "B";
}
if (anInt >= 70 & anInt <= 79){
return "C";
}
if (anInt >= 60 & anInt <= 69){
return "D";
}
else{
return "F";
}
}
public static string GetEntry() {
while (true){
Console.WriteLine("Please enter your grade or enter Quit to end program.");
string entry = Console.ReadLine();
if (entry == "Quit"){
return entry;
}
int anInt;
if (Int32.TryParse (entry, out anInt)) {
if (anInt>= 0 && anInt <= 100) {
return entry;
} else {
Console.WriteLine("Error: Please enter a valid integer!");
}
}
}
}
}
"How can I stop my average output from displaying the same letter grade as my original grade output?"
You must call DetermineGrade again with the average. The variable grade will not change by itself.
The problem is that average is a double but DetermineGrade wants an int input. You could simply change the type of the input parameter to double. int arguments will automatically be converted to double.
The method can be simplified. Since the first case returns when the input is >= 90, you don't need to test whether it is <= 89 in the second case. The same is true for the following cases.
public static string DetermineGrade(double value) {
if (value >= 90.0) return "A";
if (value >= 80.0) return "B";
if (value >= 70.0) return "C";
if (value >= 60.0) return "D";
return "F";
}
And then
string averageGrade = DetermineGrade(average);
Console.WriteLine("The average is {0} is a(n) {1}", average, averageGrade );
You can also use a switch expression (since C# 8.0) and relational patterns (since C# 9.0) and a expression bodied method (since C# 6.0):
public static string DetermineGrade(double value) =>
value switch {
>= 90.0 => "A",
>= 80.0 => "B",
>= 70.0 => "C",
>= 60.0 => "D",
_ => "F"
};
"Also how to make sentinel values case insensitve?"
Using .ToLower() is an option. Another possibility is to use
while (true) { // Infinite loop.
string entry = GetEntry();
if (String.Equals(entry, "Quit", StringComparison.OrdinalIgnoreCase)) {
break; // Exit the while loop.
}
...
}
You also have the option to use CurrentCultureIgnoreCase or InvariantCultureIgnoreCase instead. This can make a difference for the Turkish culture, because they have two different "i"s (+ one without the dot) that may be handled differently.
In simple situations, where no accents or other special or foreign characters are used, OrdinalIgnoreCase will do it.

Why cant I return the index of a value I have searched for in an array?

I have code to ask the user to enter a search value, which should then be compared against every value in the array.
If it is found then it should return every position it is found at in the array.
However when I enter a value which I know should be in the array the code will still say that it isn't.
static void Main(string[] args)
{
string[] low256 = File.ReadAllLines(#"C:\Users\Dingo Ice\Downloads\Low_256.txt");
Console.WriteLine("Choose a file to use, enter 1: Low, 2: High or 3: Mean");
int choice = Convert.ToInt32(Console.ReadLine());
//Sort Arrays into ascending order
Array.Sort(low256);
//Sort Arrays into descending order
Array.Reverse(low256);
if (choice == 1)
{
for (int i = 0; i < low256.Length; i++)
{
if (i % 10 == 0)
{
Console.WriteLine(low256[i]);
}
}
}
else
{
Console.WriteLine("Enter 1, 2 or 3");
}
Console.WriteLine("Enter an exact value to search for in the selected array");
string searchValue = Console.ReadLine();
int found = 0;
int counter = 0;
if (choice == 1)
{
foreach (var value in low256)
{
if (searchValue == value)
{
Console.WriteLine("Search value found at position: " + value);
found = 1;
}
else if (found == 0 && counter >= low256.GetUpperBound(0))
{
Console.WriteLine("The search value was not found in the selected array");
}
counter += 1;
}
}
Console.ReadLine();
}
Can you change this:
if (searchValue == value)
To:
if (searchValue.ToLower().Trim() == value.ToLower().Trim())
And see if this causes a match to be found?
Also, you mentioned that you want every position found to be returned, but in your example this doesn't happen as you only mention via a Console.WriteLine that it is found (but not even on which index). I have changed your log to the Console to include at which index it was found and the index gets added to a list of indexes found.
Does this solve your question?
static void Main(string[] args)
{
string[] low256 = File.ReadAllLines(#"C:\Users\Dingo Ice\Downloads\Low_256.txt");
Console.WriteLine("Choose a file to use, enter 1: Low, 2: High or 3: Mean");
int choice = Convert.ToInt32(Console.ReadLine());
//Sort Arrays into ascending order
Array.Sort(low256);
//Sort Arrays into descending order
Array.Reverse(low256);
if (choice == 1)
{
for (int i = 0; i < low256.Length; i++)
{
if (i % 10 == 0)
{
Console.WriteLine(low256[i]);
}
}
}
else
{
Console.WriteLine("Enter 1, 2 or 3");
}
Console.WriteLine("Enter an exact value to search for in the selected array");
string searchValue = Console.ReadLine();
searchValue = searchValue.ToLower().Trim();
List<int> indexes = new List<int>();
if (choice == 1)
{
for (int i = 0; i < low256.Length; i++)
{
string value = low256[i].ToLower().Trim();
if (searchValue == value)
{
Console.WriteLine($"Search value '{value}' found at position: '{i}'.");
indexes.Add(i);
}
}
if (indexes.Count == 0)
{
Console.WriteLine("The search value was not found in the selected array");
}
}
Console.ReadLine();
}
You could do this with LINQ by projecting your array into a ValueTuple with Select, using Where to filter, then selecting the index.
Note : The string.Compare method just gives you the option on how you want to compare the strings, remove or change the option to taste
var ary1 = new string[] { "asd", "sdf", "sdf", "sgfdfg", "dsf", "asd" };
var someValue = "asd";
var indices = ary1.Select((value, index) => (value, index)) // convert to value index tuple
.Where(pair => string.Compare(pair.value, someValue,CultureInfo.CurrentCulture, CompareOptions.OrdinalIgnoreCase) == 0)
.Select(pair => pair.index);
foreach(var index in indices)
Console.WriteLine(index);
Output
0
5
Maybe you are looking for Array.IndexOf method.
private void button1_Click(object sender, EventArgs e)
{
string[] names = { "Mathew", "Mark", "Luke", "John" };
int index = Array.IndexOf(names, "Luke");
Debug.Print(index.ToString());
//Prints 2
}

How can I get this to loop back to the start if the selection by the user isnt S, D or Y?

How do I get this to loop back to the main? I am new to coding like this, mostly just games I code so something like this shouldn't seem too hard but for the life of me I cant get it to loop
static void Main(string[] args)
{
float Age = 0;
// ask whether age will be in years, days or seconds
Console.WriteLine("In what format would you like to enter your age?
S for Seconds, D for Days, Y for Years. ");
string choice = Console.ReadLine();
// get choice
// if choose seconds
// get age
// multiply by the number of seconds in an earth year
if (choice == "s")
{
Console.WriteLine("Please enter your age in seconds");
string number = Console.ReadLine();
Age = Convert.ToInt32(number);
}
// if choose days
// get age
// multiply by the number of seconds in an earth year
if (choice == "d")
{
Console.WriteLine("Please enter your age in days");
string number = Console.ReadLine();
Age = Convert.ToInt32(number);
Age *= 86400;
}
// if choose years
// get age
// multiply by the number of seconds in an earth year
if (choice == "y")
{
Console.WriteLine("Please enter your age in years");
string number = Console.ReadLine();
Age = Convert.ToInt32(number);
Age *= 86400 * 365.25f;
}
You´d need a loop checking if the input is already correct:
bool correct;
do
{
Console.WriteLine("In what format would you like to enter your age? " +
"S for Seconds, D for Days, Y for Years. ");
string choice = console.ReadLine();
if(choice == "y") { ... correct = true; }
else if (choice == "s") { ... correct = true; }
else if (choice == "d") { ... correct = true; }
else correct = false;
} while(!correct);
The do-while loop ensures the code will execute at least once and stops when the first valid input is given.

How do I find a value in an array in the specific situation?

I am creating an array that stores a name and a bowling score from the same line and then using Split() to split the name and score into two separate arrays. Then I need to find the highest score along with the name with the highest score and write it to the console using a method somehow.
Here is what i have so far. Thanks.
const int SIZE = 10;
string[] arrayNames = new string[SIZE];
int[] arrayScores = new int[SIZE];
for (int i = 0; i < SIZE; i++){
Write("Enter the name and score of a player on one line seperated by a space or press Enter to stop ");
string input = ReadLine();
if (input == ""){
break;
}
string[] scoreInfo = input.Split();
arrayNames[i] = scoreInfo[0];
bool valid = false;
do{
if (input == ""){
break;
}
valid = int.TryParse(scoreInfo[1], out arrayScores[i]);
valid = valid && (arrayScores[i] <= 300);
} while (!valid);
}
int max = bowling.CalcHighest(arrayScores);
int min = bowling.CalcLowest(arrayScores);
int average = bowling.CalcAverage(arrayScores);
Your problem is that you aren't maintaining a reference between the name and the score.
When you read in a line you are separating the values into arrayNames[i] and arrayScores[i].
Consider using a Dictionary maybe instead of two separate arrays.
Dictionary<string, int> dict = new Dictionary<string, int>();
dict.Add(name, score);
Then do your calculations using the dictionary as a parameter rather than the array. If you're using System.Linq you can do all the calculations on the dictionary real easy:
var orderedDict = dict.OrderByDescending(d => d.Value); //This orders the dictionary by the scor
var first = orderedDict.First(); //This gets the highest score
var last = orderedDict.Last(); //This gets the lowest score
var average = dict.Sum(s => s.Value)/dict.Count(); //This is the average
var firstName = first.Key; //Name of winner
var lastName = last.Key; //Name of loser
In your for loop, you already have the highest score, you just need to keep track of it. arrayScores[i]
Here's what I'd do:
const int SIZE = 10;
string[] arrayNames = new string[SIZE];
int[] arrayScores = new int[SIZE];
int highScore = 0;
string winner = "";
for (int i = 0; i < SIZE; i++){
Write("Enter the name and score of a player on one line seperated by a space or press Enter to stop ");
string input = ReadLine();
if (input == ""){
break;
}
string[] scoreInfo = input.Split();
arrayNames[i] = scoreInfo[0];
bool valid = false;
do{
if (input == ""){
break;
}
valid = int.TryParse(scoreInfo[1], out arrayScores[i]);
valid = valid && (arrayScores[i] <= 300);
if(valid && arrayScores[i] > highScore){
highScore = arrayScores[i];
winner = arrayNames[i];
}
} while (!valid);
}
Then just grab the winner and highScore after the completion of the for loop.

Ending a loop by sentinel and parsing an input string as an integer

I am trying to continuously ask user for a number between 300-850. When the user enters a valid number, add it to the total and ask again. If the number is invalid, display an error. Before program ends, display the average of total number by amount of times of input. End program if user enters a sentinel value. I don't know how to check if user enters a sentinel value.
using System;
class CreditScores
{
static void Main()
{
var iterations = 0;
double total = 0;
int sum = 0;
double average = 0;
int count = 0;
Console.WriteLine("Enter value between 300 to 850.");
int first = int.Parse(Console.ReadLine());
//trying to get it to stop when sentinel value reached.
while (iterations < 1000)
{
iterations++;
Console.WriteLine("Enter value between 300 to 850.");
int input = int.Parse(Console.ReadLine());
//not sure how to check if input is a number or not
if(input == integer)
{
if( input < 850 && input > 300 )
{
total +=input;
}
}
else
{
break;
}
}
total = sum + total;
Console.WriteLine("Total is {0}", total);
average = total / count;
Console.WriteLine("The average is {0}", average);
}
}
Modification/fix of Your Method
Also, I would read all the way to the end for the more robust method you could use.
First thing I would change:
while (iterations < 1000)
{
...
}
To this (which we are not done yet, read to the end):
while (input != "calculate") // or some other string
{
...
}
Then, before the while starts, make input a string.
string input = "";
while (input != "calculate") // or some other string
{
...
}
Now, we declared an input variable that is already an int later on. Let's fix that.
Console.WriteLine("Enter value between 300 to 850.");
input = Console.ReadLine();
int value = 0;
if (int.TryParse(input, out value))
{
// Clearly it's a valid integer at this point
if (value < 850 && value > 300)
{
total += value;
}
}
else
{
// Wasn't a number, might be our sentinel.
if (input == "calculate")
break;
else
{
// Throw an error or something.
}
}
Now, we need to put it together and do some cleaning.
int total = 0;
int numbersEntered = 0;
string input = "";
while (input != "calculate")
{
Console.WriteLine("Enter value between 300 to 850.");
input = Console.ReadLine();
int value = 0;
if (int.TryParse(input, out value))
{
// Clearly it's a valid integer at this point
if (value < 850 && value > 300)
{
total += value;
numbersEntered++;
}
}
else
{
// Wasn't a number, might be our sentinel.
if (input == "calculate")
break;
else
{
// Throw an error or something.
}
}
}
Console.WriteLine("Total is {0}", total);
double average = (double)total / numbersEntered;
Console.WriteLine("The average is {0}", average);
(I know, long answer. But it should help you step through the problem in the future. Also, I wrote this all by memory, I can't guarantee it will compile.)
Update: just tested it, works as expected.
A more Robust Method
Lastly, and this is really the coolest method in my opinion, use a List<int> and some extension methods.
List<int> values = new List<int>();
string input = "";
while (input != "calculate")
{
Console.WriteLine("Enter value between 300 to 850.");
input = Console.ReadLine();
int value = 0;
if (int.TryParse(input, out value))
// Clearly it's a valid integer at this point
if (value < 850 && value > 300)
values.Add(value);
else
{
// Was outside our range
}
else
// Wasn't a number, might be our sentinel.
if (input == "calculate")
break;
else
{
// Throw an error or something.
}
}
Console.WriteLine("Total is {0}", values.Sum());
Console.WriteLine("The average is {0}", values.Average());
Advantages to this method? It saves a list of the values entered, allowing you to do more with them that you cannot do with the method you currently have. It also uses the int.Sum() and int.Average() extension methods rather than your own math.
What is this int.TryParse(string, out int) sorcery?
The int.TryParse(string, out int) method (as defined by MSDN) will take an input string, and return a boolean value that indicates if it would make a valid int structure or not.
In the case that the string is a valid int, then the int parameter is filled with the integer representation of the string.
I.e.:
string myString = "100";
int value = 0;
if (int.TryParse(myString, out value))
Console.WriteLine("myString was a valid int: {0}", value);
else
Console.WriteLine("myString was not a valid int.");
This version will return true and print: myString was a valid int: 100.
Example 2:
string myString = "blah";
int value = 0;
if (int.TryParse(myString, out value))
Console.WriteLine("myString was a valid int: {0}", value);
else
Console.WriteLine("myString was not a valid int.");
This version will return false, and print myString was not a valid int.. The value variable would also be 0.
Warning:
When using int.TryParse(string input, out int value), do not rely on the value parameter as 0 to indicate failure. If the input is "0", then the value will also be 0, and the method will return true.
You want to set the condition of your while loop to something that a user can trigger as false (the sentinel).
Then put a for loop inside that if you want to do a set number of iterations, for loops are better for situations where you know how many iterations you're doing.
BUT if you want to stick to while loops only, here's a quick code snippet you could use:
while (input != 0 && iterations < 1000) //or some sentinel value you choose
{
//Your logic here, now the loop will quit if if the user enters 0
//OR you run out of iterations
}
using System;
class CreditScores
{
static void Main()
{
double total = 0;
int sum = 0;
int count = 0;
Console.WriteLine("Enter value between 300 to 850.");
int first = int.Parse(Console.ReadLine());
//trying to get it to stop when sentihel value reached.
for (iterations = 0; iterations < 1000; iterations++)
{
Console.WriteLine("Enter value between 300 to 850.");
int input;
// Check number is integer
if (int.TryParse(Console.ReadLine(), out input)
{
if(input > 300 && input < 850)
{
total +=input;
}
}
else
{
break;
}
count++;
}
total = sum + total;
Console.WriteLine("Total is {0}", total);
double average = total/count;
Console.WriteLine("The average is {0}", average);
Console.ReadLine(); // Either this or run with Ctrl-F5
}
}
The behaviour would be to add the totals until the user entered something that couldn't be parsed, and then exit.
Does this work?
string sentinalValue = "done";
string input = "";
while (iterations < 1000 && input != sentinalValue)
{
iterations++;
Console.WriteLine("Enter value between 300 to 850.");
input = Console.ReadLine();
int value;
if (int.TryParse(input, out value))
{
if( value < 850 && value > 300 )
{
total +=input;
}
}
else
{
Console.WriteLine("That is not a number!");
}
}

Categories