taking specific info out of an array - c#

Below is the code I have written. What I'm trying to do is say enter 3 players names and the number of goals they have scored. Then the application should output the players name with the most goals and his number of goals. Also the application should output the lowest number of goals scored and the average goals scored. I can get the max goals scored but I cant figure out how to link the players name to goals scored. Also when I try and get the lowest goals scored I keep getting a value of 0. Thanks for the help.
{
string []player = new string[20];
double [] goalsScored = new double[20];
int numberOfPlayers;
Console.WriteLine("Enter the number of players:");
numberOfPlayers = int.Parse(Console.ReadLine());
for (int i = 0; i < numberOfPlayers; i++)
{
Console.WriteLine("Enter a players name:");
player[i]= Console.ReadLine();
Console.WriteLine("Goals scored so far this season");
goalsScored [i] = int.Parse(Console.ReadLine());
}
double max = goalsScored.Max();
double sum = goalsScored.Sum();
double average = sum / numberOfPlayers;
Console.WriteLine("Top player is: {0} with {1} goals", player, max);
Console.WriteLine("The average goals scored was:{0}",average);
double min = goalsScored.Min();
Console.WriteLine("The lowest goals scored was: {0}", min);
Console.ReadLine();
}
}
}

You should get the number of players first, then create your arrays using that number.
For example:
string[] player = new string[numberOfPlayers];
This may explain why you're always getting zero as the minimum score. If your array contains empty spots (if you entered less than 20 players/scores).
To "link" the player's name with his goals scored, you should really use a Player class so you can just have a single array of Player objects and use it for both scores and names. Then you'd end up with something like:
Console.WriteLine("Top player is: {0} with {1} goals", topPlayer.name, topPlayer.score);

You can't do this easily using arrays. You could use a Dictionary, which would allow you to look up a player's name and get the goals out. Indeed this sort of pairing of values is kind of what dictionaries are for:
//declare a dictionary string, int. The "string" is the name which we look up to get the
//second data point of "int", which will be the number of goals
Dictionary<string, int> playerGoals = new Dictionary<string, int>();
//add a couple of players, and their goal tally
playerGoals.Add("Gianfranco Zola", 44);
playerGoals.Add("Wayne Rooney", 77);
//use the string name to retrieve the int value
int rooneyGoals = playerGoals["Wayne Rooney"];
//rooneyGoals is now 77
Quicky whipped through your original code - something like this should work:
Dictionary<string, int> playerGoals = new Dictionarty<string, int>()'
int numberOfPlayers;
Console.WriteLine("Enter the number of players:");
numberOfPlayers = int.Parse(Console.ReadLine());
for (int i = 0; i < numberOfPlayers; i++)
{
Console.WriteLine("Enter a players name:");
string playerName = Console.ReadLine();
Console.WriteLine("Goals scored so far this season");
int goalsScored = int.Parse(Console.ReadLine());
playerGoals.Add(playerName, goalsScored);
}
double max = playerGoals.Values.Max();
double sum = playerGoals.Values.Sum();
double average = sum / numberOfPlayers;
Console.WriteLine("Top player is: {0} with {1} goals", player, max);
Console.WriteLine("The average goals scored was:{0}",average);
double min = playerGoals.Values.Min();
Console.WriteLine("The lowest goals scored was: {0}", min);
Console.ReadLine();

Linq solution :)
var players = player.Zip(goalsScored, (n,g) => new { Name = n, Goals = g });
var topGoalscorer = players.OrderByDescending(p => p.Goals).First();
var misser = players.OrderBy(p => p.Goals).First();
topGoalscorer.Goals // max goals
topGoalscorer.Name // player name
Using goals value:
string playerName = player[Array.IndexOf(goalsScored, min)];
Alternative solution:
int maxScoredGoals = -1;
string topGoalscorer = "";
for(int i = 0; i < numberOfPlayes; i++)
{
if (goalsScored[i] <= maxScoredGoals)
continue;
maxScoredGoals = goalsScored[i];
topGoalsocrer = player[i];
}
Suggestions: use single data structure to hold related data, i.e. player name and scored goals
public class Player
{
public string Name { get; set; }
public int Goals { get; set; }
}
Also use generic collection instead of arrays:
List<Player> players = new List<Player>();
Filling collection:
for(int i = 0; i < numberOfPlayers; i++)
{
var player = new Player();
player.Name = Console.ReadLine();
player.Goals = Int32.Parse(Console.ReadLine());
players.Add(player);
}
Getting top goalscorer:
var topGoalscorer = players.OrderByDescending(p => p.Goals).First().Name;
Or with MoreLINQ:
var topGoalscorer = players.MaxBy(p => p.Goals).Name;

You can use indirect sorting using Array.Sort(goalsScored, players); to keep a second array in sync while sorting an array. Other issues are addressed in the comments in the following code.
var numberOfPlayers = Int32.Parse(Console.ReadLine());
// Allocate the arrays with the correct size; in your code numberOfPlayers
// larger than 20 will cause trouble.
var players = new String[numberOfPlayers];
var goalsScored = new Double[numberOfPlayers];
// Fill the arrays as in your code.
// This will sort the goalsScored array and simultaneously
// bring the players array into the same order; that is called
// indirect sorting.
Array.Sort(goalsScored, players);
// The maximum number of goals scored and the associated player
// are now in the last array position.
var topPlayer = players.Last();
var maxNumberGoals = goalsScored.Last();
// You always got 0 because you always allocated arrays of size
// 20 and if you have less than 20 players all the superfluous
// entries in the array just have their default value of 0 making
// the minimum in the array 0.
var minNumberGoals = goalsScored.First();
var totalNumberGoals = goalsScored.Sum();
var averageNumberGoals = goalsScored.Average();
Unfortunately there is only out of the box support for this with arrays while it might be better to use lists and just add new players and scores until the users says that there are no more players to be entered instead of forcing the user to enter the number of players in advance.
Other answer suggest to use a more object oriented design and combine players and scored goals into a class or at least use a dictionary and I really suggest the same but I won't bother duplicating answers already here.

Related

After a while random number generator gives same number

I have a code that generates a user specified amount of random number from a range of also user specified numbers without repeats. The problem I have is that for a while the program works fine and then it just keeps giving the same number it seems, which breaks it.
Here's the whole code, some of it is in hungarian but if you want to try it for yourself to see what the problem really is: the program first asks you the range of numbers(first the minimum then the maximum number) and then the amount of numbers you want generated. After that you will see the your numbers generated... or not if it decides to not work. If you did get your numbers if you press "1" it will generate again with the same data you provided, pressing "2" will allow you to give different parameters and pressing "0" will quit the program.
If needed I can translate the program to help solve it.
using System;
using System.Collections.Generic;
namespace numgen
{
class Program
{
static int quantity, min, max, temp;
static bool check = false;
static int control = 2;
public static void Main(string[] args)
{
var gen = new List<int>();
Random rnd = new Random();
while(control > 0) {
Console.Clear();
if(control == 2) {
Console.Write("Add meg a minimum számot: ");
min = int.Parse(Console.ReadLine());
Console.Write("Add meg a maximum számot: ");
max = int.Parse(Console.ReadLine());
Console.Write("Add meg a hány számot kérsz: ");
quantity = int.Parse(Console.ReadLine());
}
gen.Clear();
//gen.Add(rnd.Next(min, max));
while(gen.Count < quantity) {
temp = rnd.Next(min, max);
foreach(int num in gen) {
if(temp == num) {
check = true;
break;
}
}
if(!check) {
gen.Add(temp);
//Uncomment to see number getting generated and when the program breaks
//Console.WriteLine(gen[gen.Count-1]);
}
}
gen.Sort();
foreach(int num in gen){
Console.WriteLine(num);
}
Console.WriteLine("\n[2] Új adatok megadása");
Console.WriteLine("[1] Számok újragenerálása");
Console.WriteLine("[0] Kilépés");
control = int.Parse(Console.ReadLine());
}
}
}
}
A HashSet is an excellent choice for this task. Elements are added as a key--so it will refuses any value that is already in the set.
Try something like this:
private static void TestHashSet(int min, int max, int quantity)
{
var gen = new HashSet<int>();
Random rnd = new Random();
while (gen.Count < quantity)
{
var temp = rnd.Next(min, max);
gen.Add(temp);
}
gen.AsEnumerable().OrderBy(s => s).ToList().ForEach(x => Console.WriteLine(x));
}
You are not setting check back to false, so your code breaks after the first duplicate is found.
You're not setting check back to false at any point in time.
Once you get the first collision you cease adding value to the list, so while (gen.Count < quantity) will never be true.
You might want to consider using a keyed Dictionary which will handle the indexing for you rather than some logic.
Also you're not checking if quantity is greater than the provided range. If it is you will always get collisions.
Consider a keyed dictionary, to take the logic checking away and let the Dictionary object take care of it.
var gen = new Dictionary<int, int>();
if (quantity > (max - min))
throw new ArgumentOutOfRangeException("Quantiy must be smaller than range");
while (gen.Count < quantity)
{
temp = rnd.Next(min, max);
if(!gen.ContainsKey(temp))
gen.Add(temp, temp);
}
foreach (int num in gen.Values)
{
Console.WriteLine(num);
}
Issues found in your script
When you set check = true;, you Never change it to false. gen.Add() never happens.
if someone selects minimum 2, max 3 and ask for 10, it will always have duplicate values.. Your code doesnt allow that and will run infinite loop. Calculate total numbers that can be generated between the two numbers and see if it can produce required quantity.
Not an issue but I would recommend using gen = new List<int>(); instead of Clear()
You can use Contains method to quickly check if the value is part of the list or not (instead of iterating over the entire list each time).
Updated your code and got it working like this,
while (control > 0)
{
Console.Clear();
if (control == 2)
{
Console.Write("Add meg a minimum számot: ");
min = int.Parse(Console.ReadLine());
Console.Write("Add meg a maximum számot: ");
max = int.Parse(Console.ReadLine());
Console.Write("Add meg a hány számot kérsz: ");
quantity = int.Parse(Console.ReadLine());
}
else if (control == 1)
gen = new List<int>();
if (max - min < quantity)
Console.WriteLine($"You cannot generate {quantity} between [{min} and {max}]");
else
{
while (gen.Count < quantity)
{
temp = rnd.Next(min, max);
if (!gen.Contains(temp))
gen.Add(temp);
}
gen.Sort();
gen.ForEach(x => Console.WriteLine(x));
}
Console.WriteLine("\n[2] Új adatok megadása");
Console.WriteLine("[1] Számok újragenerálása");
Console.WriteLine("[0] Kilépés");
control = int.Parse(Console.ReadLine());
}

Get sequence of random n numbers that add up to something but only from a specific set of numbers

What I need is:
e.g:
Sum should be equal to:
120 (user input)
Number of numbers/items:
80 (user input)
Range of numbers to be used in set(from):
0 (user input)
Range of numbers to be used in set(to):
4 (user input)
Output:
1,1,3,2,1,1,0,0,1,1,2,1,0,2,3,3,1,2,0,0,0,1,3,2,3,1,0,0,2,3,2,3,2,2,1,1,0,0,2,0,1,0,1,1,3,3,1,3,1,0,0,3,2,1,0,0,2,1,2,3,0,3,1,1,3,3,2,2,1,1,3,1,3,3,3,3,3,1,2,0
These are all numbers that are between 0 and 4, their sum is 120 and are 80 in total.
What i've done is:
static void Main(string[] args)
{
bool loopOn = true;
Program p = new Program();
Console.WriteLine("____________________________________________________________________________");
Console.WriteLine("");
Console.WriteLine("Sum should be equal to:");
int sum = int.Parse(Console.ReadLine());
Console.WriteLine("Number of items:");
int items = int.Parse(Console.ReadLine());
Console.WriteLine("Range(from):");
int from = int.Parse(Console.ReadLine());
Console.WriteLine("Range(to):");
int to = int.Parse(Console.ReadLine());
while (loopOn == true)
{
List<int> number_list = p.createNumberSet(items, from, to);
if (number_list.Sum() == sum)
{
loopOn = false;
Console.WriteLine("____________________________________________________________________________");
Console.WriteLine("Start");
number_list.ForEach(Console.WriteLine);
Console.WriteLine("Stop");
Console.WriteLine("____________________________________________________________________________");
}
}
Console.WriteLine("Press any key to exit....");
Console.ReadLine();
}
public List<int> createNumberSet(int itemNumber, int range_from, int range_to)
{
List<int> number_set = new List<int>();
Random r = new Random();
for (int i = 0; itemNumber > i; i++)
{
number_set.Add(r.Next(range_from, range_to));
}
return number_set;
}
But this seems extremely in-efficent and doesn't seem to work with a lot of other examples. Does anyone have a better way of doing this?
Well, I am a bit lazy right now, so this is just an idea
Keep the first part:
bool loopOn = true;
Program p = new Program();
Console.WriteLine("____________________________________________________________________________");
Console.WriteLine("");
Console.WriteLine("Sum should be equal to:");
int sum = int.Parse(Console.ReadLine());
Console.WriteLine("Number of items:");
int items = int.Parse(Console.ReadLine());
Console.WriteLine("Range(from):");
int from = int.Parse(Console.ReadLine());
Console.WriteLine("Range(to):");
int to = int.Parse(Console.ReadLine());
Now, first of all, check is a solution exists:
if (from * items > sum) {
// There is no solution, handle accordingly
}
Let's focus on the interesting part now:
First create the list of necessary items
int[] number_set = new int[items];
for(int i = 0; i < items; i++) {
number_set[i] = from;
}
Find the difference between the wanted sum and the current sum of the list
int left_to_add = sum - from * items;
int idx = 0;
Random r = new Random();
while(left_to_add > 0) {
int toAdd = 0;
if (left_to_add < range_to - range_from) {
toAdd = r.Next(1, left_to_add);
} else {
toAdd = r.Next(1, range_to - range_from);
}
left_to_add -= toAdd;
number_set[idx] += toAdd;
idx++;
}
What's left to do is, convert the array to a list and shuffle it.
(I forgot that you actually can access list items by index, so there is no need to use an array as I did here)
At the algorithm level, this is what I would try:
Determine the number of each element, n[0], n[1], n[2], n[3] in your example (i.e. number of 0, number of 1 ...) and then generate a simple sequence by concatenating n[0] "0", n[1] "1", n[2] "2" and n[3] "3". Finally, a random sequence is obtained by performing a random permutation on this simple sequence.
The problem is therefore to determine the n[i].
The first step is to determine the average values of these n[i]. It your example, it is simple, as we can take average n_av[i]=20 for all index i.
In a more general case, we have to insure that
sum_i n_av[i]*i = sum_target (120 here) (1)
knowing that
sum_i (n[i]) = n = 80 here. (2)
In the general case, there is no necessary one unique good solution. I will try to propose an example of solution here if you provide an example of a difficult scenario.
The second step consists in selecting some random n[i] values around these average values. One possibility is to generate rounded Gaussian variables: we already know the averages, we just need to determine the variances. One possibility is to consider the variance that we will get if we were generating directly the random values, i.e. by considering the variance of the corresponding binomial variable :
var = n p(1-p). Here p[i] = n_av[i]/n
The last step consists in adjusting the values of the n[i] such that the sum of the n[i] is equal to the target. This is simply obtained by slightly increasing or decreasing some n[i] values.

C# - Check how many times a value appears in array and find indexes

I have to write a simple program where you have to input student names and their average grade and then print out the highest average grade and who it belongs to. There are several topics here on how to find if value appears in array. The thing i'm struggling with is what to do if there are more than 1 students with the max average grade.
Here's what I have so far:
Console.WriteLine("Enter the overall count of students.");
int stuCount = Convert.ToInt32(Console.ReadLine());
string[] name = new string[stuCount];
double[] avg = new double[stuCount];
for (int i = 0; i < stuCount; i++)
{
Console.WriteLine("Enter the name of student # {0}.", i + 1);
name[i] = Console.ReadLine();
Console.WriteLine("Enter the average grade of {0}.", name[i]);
avg[i] = Convert.ToDouble(Console.ReadLine());
}
// Finding the max average
double maxAvg = avg[0];
for (int i = 1; i < stuCount; i++)
{
if (avg[i] > maxAvg)
{
maxAvg = avg[i];
}
}
// Displaying the max average
Console.WriteLine("The highest average grade is {0}.", maxAvg);
So, can I use Array.IndexOf() method to find multiple indices?
Thank you.
Consider using a class to represent the grades as so;
class Grade {
public String Name {get;set;}
public double Average {get;set;}
}
Then your code can be more like;
Console.WriteLine("Enter the overall count of students.");
int stuCount = Convert.ToInt32(Console.ReadLine());
List<Grade> allGrades = new List<Grade>();
for (int i = 0; i < stuCount; i++)
{
Console.WriteLine("Enter the name of student # {0}.", i + 1);
var name = Console.ReadLine();
Console.WriteLine("Enter the average grade of {0}.", name[i]);
var avg = Convert.ToDouble(Console.ReadLine());
Grade current = new Grade(){
Name = name,
Average = avg
};
allGrades.Add(current);
}
// Finding the max average
double maxAvg = allGrades.Max(g => g.Average);
var highestGrades = allGrades.Where(g => g.Average == maxAvg);
Console.WriteLine("The following Student(s) have the highest average grade:");
foreach(var grade in highestGrades){
// Displaying the max average
Console.WriteLine("Student: {0}. Grade: {1}.", grade.Name, grade.Average);
}
}
Another way is creating a class containing two properties (name and average grade), then generate a List and fill it in a for cycle. The next step is order by descending the list through average grade and select the first N element equals. After that you can simply print the result using a ForEach
After you've found the highest average just loop again through the averages array to see which ones are the max ones and print the stud using the index.
Console.WriteLine("The highest average grade is {0}.", maxAvg);
Console.WriteLine("The students with this average grade are");
for (int i = 0; i < stuCount; i++)
{
if (avg[i] == maxAvg)
{
Console.WriteLine(name[i]);
}
}

Getting an average from a C# array

I have been working on this assignment for a couple days now. I have written all the code myself. I'm not looking to cheat or have someone do my work for me, but for the life of me, I can't get this to work correctly.
The problem I'm having is that when I try to average numbers in an array, instead of dividing by just the number of entries, it's dividing by the total allowed entries into the array.
For example. I enter 2 values into an array that can hold 100 values, instead of dividing by 2, it divides by 100.
How do I get it to divide by just the number of entries? Here is what I have:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication6
{
class Program
{
static void InputData(string[] player, int[] score, ref int numPlayer)
{
// input items up to the number of the array size
while (numPlayer < player.Length)
{
Console.Write("Enter player name (Q to quit): ");
player[numPlayer] = Console.ReadLine();
if ((player[numPlayer] == "Q") || (player[numPlayer] == "q"))
{
Console.WriteLine();
break;
}
else
{
Console.Write("Enter score for " + player[numPlayer] + ": ");
score[numPlayer] = Convert.ToInt32(Console.ReadLine());
numPlayer++;
}
}
}
static void DisplayPlayerData(string[] player, int[] score, int numPlayer)
{
Console.WriteLine("Name Score");
for (int i = 0; i < numPlayer; i++)
Console.WriteLine("{0, -16} {1, 8}", player[i], score[i]);
}
static double CalculateAverageScore(int[] score, ref int numPlayer)
{
double avgScore;
double total = 0;
for (int i = 0; i < numPlayer; i++)
{
total += score[i];
}
avgScore = total / score.Length;
Console.WriteLine("Average Score:" + avgScore);
return avgScore;
}
static void DisplayBelowAverage(string[] player, int[] score, int numPlayer)
{
double avgScore = CalculateAverageScore(score, ref numPlayer);
Console.WriteLine("Players who scored below average");
Console.WriteLine("Name Score");
for (int i = 0; i < numPlayer; i++)
{
if (score[i] < avgScore)
{
Console.WriteLine("{0, -16} {1}", player[i], score[i]);
}
}
}
static void Main(string[] args)
{
//Variables
string[] player = new string[100];
int[] score = new int[100];
int numPlayer = 0;
InputData(player, score, ref numPlayer);
DisplayPlayerData(player, score, numPlayer);
CalculateAverageScore(score, ref numPlayer);
DisplayBelowAverage(player, score, numPlayer);
Console.ReadLine();
}
}
}
You have a numPlayer variables that stands for a number of entered players.
Just use it.
Replace
avgScore = total / score.Length;
with
avgScore = total / numPlayer;
Your code has some very strange points.
For example, you call CalculateAverageScore(score, ref numPlayer); in a Main(). However, you are not using a return value. This method is properly called in a DisplayBelowAverage method.
In general, it looks wrong - refs, static-sized array with dynamic number of values, non-format console writeline etc.
Just for you information. Read this once. Maybe some code lines will help you. Maybe, you won't find something new, unknown or interesting.
This is how I would solve this problem:
public class Program
{
private const string InputTerminationString = "Q";
public static void Main()
{
List<Player> players = new List<Player>(); // p. 1, 4
while (true)
{
Console.Write("Enter player name ({0} to quit): ", InputTerminationString);
string name = Console.ReadLine();
if (name == InputTerminationString) break; // p. 2
Console.Write("Enter score for {0}: ", name); // p. 3
int score = int.Parse(Console.ReadLine());
players.Add(new Player { Name = name, Score = score });
}
Console.WriteLine("Name Score");
players.ForEach(x => Console.WriteLine("{0, -16} {1, 8}", x.Name, x.Score)); // p. 5
double average = players.Average(x => x.Score); // p. 6
Console.WriteLine("Average score: {0:F2}", average); // p. 3
Console.WriteLine("Players who scored below average");
Console.WriteLine("Name Score");
players
.Where(x => x.Score < average) // p. 7
.ToList()
.ForEach(x => Console.WriteLine("{0, -16} {1, 8}", x.Name, x.Score)); // p. 5
}
}
public class Player
{
public string Name { get; set; }
public int Score { get; set; }
}
Now, step by step:
Use Player class. It is pretty inconvenient to pass two independent arrays of names and scores. Moreover, it is not safe and proper in general. A name and a score of a player are properties if a single player and should be stored together either in struct or class.
Use constants. If you need to change 'Q' termination string to 'Exit', you will be able to do this in a second without looking through the code.
Use formatted Console.WriteLine. It works liks String.Format and you don't need to concatenate strings.
Some info here: https://msdn.microsoft.com/en-us/library/828t9b9h(v=vs.110).aspx
Use dynamic collection List. Array is good for storing and rapid accessing to range of values of known length. Since a user enters values one by one, you never know if he will enter 0, 1 or 90000 values. List collection will help you with it.
Some info here: http://www.dotnetperls.com/list
You can use ForEach method which executes the given code for every item in a collection. Using ForEach with lambda-expressions makes code shorter and more readable.
Some info here: https://msdn.microsoft.com/en-us/library/bwabdf9z(v=vs.110).aspx
Use Average function which calculates the average of a collection. In case of int[] you can use arr.Average(). However, in case of Class object, you need to describe the logic of calculation of average value using lambda-expression.
Some info here: http://www.dotnetperls.com/average
LINQ Where expression lets you filter your collection.
Some info here: http://www.dotnetperls.com/where
Instead of writing CalculateAverageScore the you can make use of LINQ's Average method:
double avgScore = score.Average();
Console.WriteLine("Average Score:" + avgScore);
Forthermore it is better not to mix calculating with I/O, so:
static double CalculateAverageScore(int[] score) {
return score.Average();
}
Or since you use an array, use the sum:
static double CalculateAverageScore(int[] score, ref int numPlayer) {
return (double) score.Sum()/numPlayer;
}
and do the printing in the Main:
static void Main(string[] args) {
//Variables
string[] player = new string[100];
int[] score = new int[100];
int numPlayer = 0;
InputData(player, score, ref numPlayer);
DisplayPlayerData(player, score, numPlayer);
double avgScore = CalculateAverageScore(score, ref numPlayer);
Console.WriteLine("Average Score:" + avgScore);
DisplayBelowAverage(player, score, numPlayer);
Console.ReadLine();
}
online Ideone demo.
You furthermore better modify the array to a List. Here there is also no reason to use the ref keyword in all these methods, nor to make them static.

c#, using .length method

I have a method that needs to do a calculation based upon the length of an array. I am using the .length method for the calculation, but the method is doing arithmetic with the max length of the array (which I have declared as 10). This is the loop I am using to get data from the user. I know it isn't the ideal way to sort array data, but this is for a homework assignment, and it revolves around using the .Split method correctly (which isn't the problem I'm having).
for (int i = 0; i < MAX; i++)
{
Console.Write("Enter a name and a score for player #{0}: ", (i + 1));
string input = Console.ReadLine();
if (input == "")
{
// If nothing is entered, it will break the loop.
break;
}
// Splits the user data into 2 arrays (integer and string).
string[] separateInput = input.Split();
name [i] = separateInput[0];
score [i] = int.Parse(separateInput[1]);
}
Here is the method I am using to calculate the average score:
static void CalculateScores(int[] score)
{
int sum = 0;
int average = 0;
for (int i = 0; i < score.Length; i++)
{
sum += score[i];
average = sum / score.Length;
}
Console.WriteLine("The average score was {0}", average);
I am calling the method like this:
CalculateScores(score);
Edit: My arrays are declared:
int[] score = new int[MAX]; //MAX == 10.
string[] name = new string[MAX];
The CalculateScores method is doing the math as though score.Length is always 10, no matter how many different combinations of scores I input to the console. I can't figure out if it's because my loop to gather input has been done incorrectly, or my CalculateScores method is flawed. Thanks in advance.
Edit: to clarify, I am just confused at why I can't get the correct value out of CalculateScores.
Length always represents the size of the array, which if you've instantiated as 10, then it will always be 10, regardless of how many items you've filled.
There are lots of ways of solving your problem, but I'd go with the simple one of not using length in your calculation, but rather just storing the number of items in a separate variable:
int numItems = 0;
for(int i=0;i<MAX;i++)
{
Console.Write("Enter a name and a score for player #{0}: ", (i + 1));
string input = Console.ReadLine();
if (input == "")
{
break; // if nothing is entered, it will break the loop
}
numItems++;
...
}
static void CalculateScores(int[] score, int numItems)
{
// don't use Length at all, use numItems instead
}
Arrays are generally used for fixed sized data, so the Length property reflects how many items the array can hold rather than the amount of elements in the array. The simplest fix would be to use a List(T), which is used for variadic data, instead.
// A nice abstraction to hold the scores instead of two separate arrays.
public class ScoreKeeper
{
public string Name { get; set; }
public int Score { get; set; }
}
var scores = new List<ScoreKeeper>();
for (int i = 0; i < MAX; i++)
{
Console.Write("Enter a name and a score for player #{0}: ", (i + 1));
string input = Console.ReadLine();
if (input == "")
{
// If nothing is entered, it will break the loop.
break;
}
// Splits the user data into 2 arrays (integer and string).
string[] separateInput = input.Split();
scores.Add(new ScoreKeeper { Name = separateInput[0], Score = int.Parse(separateInput[1]) });
}
static void CalculateScores(ICollection<ScoreKeeper> scores)
{
// We take advantage of Linq here by gathering all the
// scores and taking their average.
var average = scores.Select(s => s.Score).Average();
Console.WriteLine("The average score was {0}", average);
}
checking maually:
int sum = 0;
int average = 0;
int length;
for (int i = 0; i < MAX; i++) {
if(name[i]!=string.empty) {
sum += score[i];
length=i+1;
}
}
average = sum / length;
Console.WriteLine("The average score was {0}", average);

Categories