How do I split an array into two different arrays? - c#

I can't seem to figure out how to fix my code so that it works. I need the user to be able to input their first name then space then the what they scored. Then I need to split the array into two different arrays and pass them to the four different methods to display to the user what they scored, etc. Can anyone help me figure this problem out?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace proj09LEA
{
class Program
{
static void Main(string[] args)
{
// declare and array of integers
int[] array = new int[10];
Console.WriteLine("\nSaturday Coder's Bowling Team");
Console.WriteLine("Enter in a name and score for each person on the team.");
Console.WriteLine("For example, Mary 143. Just hit Enter when you are done.\n");
// fill an array with user input
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine("Enter in a name and score: ");
string userInput;
string[] parsedInput;
parsedInput = userInput.Split();
string name = parsedInput[0];
int score = int.Parse(parsedInput[1]);
}
Console.WriteLine("------------ Input Complete ------------\n");
Console.WriteLine("Here are the scores for this game:");
DisplayScore(array);
HighScore(array);
LowScore(array);
AverageScore(array);
Console.WriteLine("Press Enter to continue. . .");
Console.ReadLine();
}
static void DisplayScore(int[] array)
{
foreach (int n in array)
{
Console.WriteLine("{0}'s score was {0}.\n", array);
}
}
static void HighScore(int[] array)
{
int max = array.Max();
Console.WriteLine("Congratulations {0}, your score of {0} was the highest.", max);
}
static void LowScore(int[] array)
{
int min = array.Min();
Console.WriteLine("{0}, your score of {0} was the lowest. Better get some practice.", min);
}
static void AverageScore(int[] array)
{
int sum = array.Sum();
int average = sum / array.Length;
Console.WriteLine("The average score for this game was {0:d}.", average);
}
}
}

If you absolutely have to use simple primitive arrays, you would need two distinct arrays of the same size, to hold the names as strings and scores as ints:
class Program
{
const int MaxScores = 10; // .. Use a constant to ensure the sizes remain in sync
static void Main(string[] args)
{ ///
string[] names = new int[MaxScores];
int[] scores = new int[MaxScores];
// ... parse names into names[] and scores into scores[]
DisplayScore(names, scores);
You would then need to pass both arrays to the various methods:
static void DisplayScore(string[] names, int[] scores)
{
for(int i=0; i < MaxScores; i++)
{
Console.WriteLine("{0}'s score was {1}.\n", names[i], scores[i]);
}
}
// etc
However, there are better ways to do this, e.g. by defining a custom class for the tuple of Name, Score:
class PersonScore
{
public string Name {get; set;}
public int Score {get; set;}
}
You can then declare and pass the single array of PersonScore[] around.
PersonScore[] personScores = new PersonScore[MaxScores];
for (... prompting the user for data)
{
... parsing user input
personScores[i] = new PersonScore{Name = name, Score = score};
}
DisplayScore(personScores); // Pass around the single array
static void DisplayScore(IEnumerable personScores)
{
foreach(var personScore in personScores)
{
Console.WriteLine("{0}'s score was {1}.\n", personScore.Name, personScores.Score);
}
}
// etc - other methods
As others have mentioned, other collections are also possible alternatives to an array, most commonly List.

You can do like this. Just use Console.ReadLine() to get user input. This is what you do in your code. There are better ways to do this but following will solve your problem.Also you need to perform validation as well.
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine("Enter in a name and score: ");
string userInput = Console.ReadLine();
string[] parsedInput;
parsedInput = userInput.Split(' ');
string name = parsedInput[0];
int score = int.Parse(parsedInput[1]);
array[i] = score;
}

Why you need to split array in to two arrays on containing names and other containing score. Its better to create a structure having String field for name and integer field for score and write Comparator for sorting the Array containing elements of this Data structure type and sort them.
It will solve all your problems and that too efficiently.

Not many data integrity checks in the methods you are using, but here are the extensions I use to split arrays or any type of enumerable. I have not tested these all that much, so I cannot guarantee that they will work. I have removed all my input validation, but I suggest you add those back your own way.
public static List<List<T>> Split<T>(this IEnumerable<T> collection, Int32 groupSize)
{
var collectionList = collection.ToList();
if (groupSize > collectionList.Count)
groupSize = collectionList.Count;
var chunks = new List<List<T>>();
while (collectionList.Any())
{
var chunk = collectionList.Take(groupSize);
chunks.Add(chunk.ToList());
collectionList = collectionList.Skip(groupSize).ToList();
}
return chunks;
}
public static List<List<T>> Split<T>(this IEnumerable<T> collection, Func<T, Boolean> splitFunction)
{
var collectionList = collection.ToList();
if (collectionList.IsNullOrEmpty())
return new List<List<T>>();
var indices = collectionList.FindIndices(splitFunction); // Custom method that searches for the indices that satisfy the predicate and returns the index of each matching item in the list.
if (indices.IsNullOrEmpty()) // equivalent to indices == null || !indices.Any()
return new List<List<T>> { collectionList };
var chunks = new List<List<T>>();
var lastIndex = 0;
if (indices[0] > 0)
{
chunks.Add(collectionList.Take(indices[0]).ToList());
lastIndex = indices[0];
}
for (var i = 1; i < indices.Count; i++)
{
var chunkSize = indices[i] - lastIndex;
var chunk = collectionList.Skip(lastIndex).Take(chunkSize).ToList();
if (chunk.IsNullOrEmpty())
{
break;
}
chunks.Add(chunk);
lastIndex = indices[i];
}
if (collectionList.Count - lastIndex > 0)
{
var lastChunk = collectionList.Skip(lastIndex).ToList();
chunks.Add(lastChunk);
}
return chunks;
}

Related

How do you make multiple instances from a class into an array with a loop in C#

I want the user to be able to specify the number of instances there are. I find that a good way to do this is using a for loop.
class Instance
{
public string name;
public int health;
public int dmg;
public Instance()
{
name = Instance;
health = 100;
dmg = 10;
}
class Program {
static void Main(string[] args) {
instance[] instanceArray = new instance
Console.WriteLine("how many instances will there be?");
string inp = Console.ReadLine();
for (int i = 0; i >= inp; i++) {
//TODO: I don't know what would go in here
}
}
}
You should create an instance in the for loop and assign it to array's item:
static void Main(string[] args) {
// In case of array, you should specify its length beforehead
// So, let's ask user about the number of instances to create
Console.WriteLine("how many instances will there be?");
// Note, int imp (not string): number of instances must be integer
// like 3, 5, 8, not string as "bla-bla-bla"
//TODO: int.TryParse is a better approach
int inp = int.Parse(Console.ReadLine());
// We create an array to hold inp instances
instance[] instanceArray = new instance[inp];
// Time to create inp instances and put them to array:
for (int i = 0; i < inp; i++) {
// Create an instance and assign it to i-th item:
instance[i] = new Instance();
}
// from now you have instance array with inp items
}
A bit shorter way to create the same array is Linq:
using System.Linq;
...
instance[] instanceArray = Enumerable
.Range(1, inp)
.Select(_ => new Instance())
.ToArray();
You can use Enumerable.Range for that:
instance[] instanceArray = Enumerable.Range(0, inp).Select(i => new instance()).ToArray();
Or just initiate the Objects via the loop like you started doing:
instance[] instanceArray = new instance[inp];
for (int i=0; i<inp ;++i){
instance[i] = new instance();
}

How to loop through array to find all occurrences of an element C#

I'm pretty new to programming,
I have two arrays that correspond with eachother.
The First displays student names the other displays the students grade.
My goal is to loop through the arrays and print out all of the students who have the grade
87 for example.
As of right now I am able to print the first person with that grade, however the loop ends once it finds the first grade.
I'm having trouble figuring out how to find ALL of the people with that grade. Any help would be appreciated. Thanks
public static void OptionTwo()
{
LoadArray();
Console.WriteLine("Enter a student grade to see all students with that grade");
int userInput = Convert.ToInt32(Console.ReadLine());
int subscript;
subscript = Search(studentGrade, userInput, ref counter);
ShowResults(userInput, subscript, counter);
}
public static int Search(int[] studentGrade, int userInput, ref int counter)
{
counter = 0;
for (int s = 0; s < studentGrade.Length; s++)
{
counter++;
if (studentGrade[s] == userInput)
return s;
}
return -1;
}
public static void ShowResults(int userInput, int subscript, int counter)
{
//LOOP THROUGH ARRAY
Console.WriteLine();
Console.WriteLine("The following students have that grade: ");
Console.WriteLine();
if (subscript == -1)
Console.WriteLine("{0} is NOT in array, # of comparisons is {1}",
userInput, counter);
else
Console.WriteLine("{0} {1}", studentName[subscript].PadRight(20), studentGrade[subscript].ToString().PadRight(5));
}
Good programming is the art of reducing cognitive load. In your architecture, you - the programmer - know that both arrays are related to each other. If you create a Student class as such:
public class Student
{
public string Name;
public int Grade;
}
Now you can create a
var students = new List<Student>();
At this point, the compiler knows to associate student names and their grades, and you don't have to remember which arrays are correlated.
You can now return your filtered list using System.Linq as such:
return students.Where(x => x.Grade == 87);
You have reduced cognitive load. This may seem trivial for your example, but it becomes central to good programming in a large organization where you will spend most of your time maintaining someone else's code.
First, let's state the problem. We have two arrays:
string[] studentName = new string[] {
"Amy", "Bob", "Charly", "Dimitry", "Eva",
};
int[] studentGrade = new int[] {
80, 70, 80, 95, 68,
};
And you want to get all the students with the given grade. E.g. "Amy" and "Charly" for 80.
If it's your case you have to scan both arrays:
private static List<string> Search(string[] studentName, int[] studentGrade, int grade) {
List<string> result = new List<string>();
// Let's use good old for loop instead of Linq
for (int i = 0; i < studentGrade.Length; ++i)
if (studentGrade[i] == grade)
result.Add(studentName[i]);
return result;
}
public static void ShowResults(int userInput) {
Console.WriteLine();
Console.WriteLine("The following students have that grade: ");
Console.WriteLine();
List<string> list = Search(studentGrade, studentName, userInput);
if (list.Count <= 0)
Console.WriteLine("{0} is NOT in array", userInput);
else
Console.WriteLine("{0} {1}", string.Join(", ", list), userInput);
}
Linq is perfect for it:
var choosenGrades = studentGrade.Where(x=>x == userInput).ToList();
Remember to add import System.Linq
The reason your loop is ending after one is because you are returning the first instance of the subscript and the function ends there.
you should create a list of subscripts to return.
so you search function should be changed to something like this
public static List<int> Search(int[] studentGrade, int userInput, ref int counter)
{
var listOfSubscripts = new List<int>();
counter = 0;
for (int s = 0; s < studentGrade.Length; s++)
{
counter++;
if (studentGrade[s] == userInput)
listOfSubscripts.Add(s);
}
return listOfSubscripts;
}
And then your show results function should be like
public static void ShowResults(int userInput, List<int> subscripts, int counter)
{
//LOOP THROUGH ARRAY
Console.WriteLine();
Console.WriteLine("The following students have that grade: ");
Console.WriteLine();
if (subscript == -1)
Console.WriteLine("{0} is NOT in array, # of comparisons is {1}",
userInput, counter);
else
{
foreach(var subscript in subscripts)
{
Console.WriteLine("{0} {1}", studentName[subscript].PadRight(20), studentGrade[subscript].ToString().PadRight(5));
}
}
}

C# Dice Roll - Assigning scores to values

Currently working on a project and need some help. Still relatively new to c#. I have created a dice rolling game in which 5 dice are rolled at once in turns between 2 players. What I am stuck on is checking through these values for a three of a kind and assigning points .For example, A player presses enter and one appears three times then the player should receive three points or if four appears three times then the player receives the points. I have tried lots of different methods using if statements and for loops but cant seem to get it working. My code is provided below.Any help would be appreciated.
Thanks
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Dice_v4
{
class Game
{
static void Main(string[] args)
{
Random RandomNum = new Random();
Player[] player1 = new Player[5];
Die[] myDie = new Die[5];
for (int i = 0; i < 5; i++)
{
myDie[i] = new Dice_v4.Die(RandomNum);
player1[i] = new Dice_v4.Player();
}
for (int i = 0; i < 2; i++) // Number of players
{
Console.Write("Enter Name for Player {0}:", i + 1);
string NewName = Console.ReadLine();
player1[i].SetName(NewName);
}
Console.WriteLine();
for (int j = 1; j < 20; j++)
{
for (int i = 0; i < 2; i++)
{
myDie[i].roll();
Console.WriteLine("{0} Rolled:{1} on the first dice", player1[i].GetName(), myDie[i].GetTopNumber());
Console.WriteLine("{0} Rolled:{1} on the second dice", player1[i].GetName(), myDie[i].GetTopNumber1());
Console.WriteLine("{0} Rolled:{1} on the third dice", player1[i].GetName(), myDie[i].GetTopNumber2());
Console.WriteLine("{0} Rolled:{1} on the fourth dice", player1[i].GetName(), myDie[i].GetTopNumber3());
Console.WriteLine("{0} Rolled:{1} on the fifth dice", player1[i].GetName(), myDie[i].GetTopNumber4());
Console.WriteLine("Total Throws:{0}", j);
Console.ReadLine(); }
}
}
}
class Die
{
private int NumberTop1; //attributes
private int NumberTop2;
private int NumberTop3;
private int NumberTop4;
private int NumberTop5;
int threepoints = 0;
private Random RandomNumGenerator;
public Die(Random RandomGenerator) // constructor
{
RandomNumGenerator = RandomGenerator; // initialises random number
}
public void roll()
{
NumberTop1 = RandomNumGenerator.Next(1, 6);
NumberTop2 = RandomNumGenerator.Next(1, 6);
NumberTop3 = RandomNumGenerator.Next(1, 6);
NumberTop4 = RandomNumGenerator.Next(1, 6);
NumberTop5 = RandomNumGenerator.Next(1, 6);
// generates random number / / Number of dice to be rolled
Console.WriteLine("\tTotal score = {0}", threepoints);
}
public int GetTopNumber()
{
return NumberTop1; // Returns number on top which equals dice roll
}
public int GetTopNumber1()
{
return NumberTop2;
}
public int GetTopNumber2()
{
return NumberTop3;
}
public int GetTopNumber3()
{
return NumberTop4;
}
public int GetTopNumber4()
{
return NumberTop5;
}
}
class Player
{
private string Name;
public void SetName(string NewName) // constructor
{
Name = NewName; // initalises name
}
public string GetName()
{
return Name; // Returns name when called
}
}
}
Advice:
Whenever you have variables or properties called something1, something2, ... - you're probably doing something wrong, and you probably want to use a list, array, hashmap...
My idea here would be to add all numbers to a list and then perhaps iterate to make a dictionary where key is the dice value and value is the count. Or you can do something else, depending which format you need for later operations.
List<int> diceValues = new List<int>();
diceValues.Add(die.GetTopNumber());
diceValues.Add(die.GetTopNumber1());
diceValues.Add(die.GetTopNumber2());
diceValues.Add(die.GetTopNumber3());
diceValues.Add(die.GetTopNumber4());
Now that you have them in a list, you can do something like:
var values = new Dictionary<int, int>();
foreach(var item in diceValues) {
if(values.Keys.Contain(item)) {
values[item]++;
} else {
values[item] = 1;
}
}
After this loop you will have a list of Dictionary items where a key will be the dice value, and the value the number of dice with that value.
E.g. if someone threw two threes, and two deuces and one four, the dictionary would look:
Key: 2, Value: 2
Key: 3, Value: 2
Key: 4, Value: 1
By iterating through these you can later make a scoring system...
I would remove these properties all along and use a list or array instead.
You declare a list:
public List<int> Roles { get; private set; }
And your roll method can become:
public void roll()
{
this.Roles = Enumerable.Range(1, 5)
.Select(i => RandomNumGenerator.Next(1, 6))
.ToList();
// Check for three of a kind:
bool threeOfAKind = this.Roles.GroupBy(i => i).Any(g => g.Count() >= 3);
// rest of your logic
Console.WriteLine("\tTotal score = {0}", threepoints);
}
Later you can access each individual roll by this.Roles[numOfRoll]

Difficulty with passing arrays and manipulating data in arrays (Homework) c#

So I am doing a Homework assignment for c#. The assignment requires the use of 2 arrays, one to hold names and the other to hold scores. We are then to calculate the average score, display the below average scores, and display the scores according to name. I am having a significant amount of difficulty passing the arrays by reference/value in order to use the data in them and maintain my code using separate modules. The arrays have to hold up to 100 individual pieces of data.
class Program
{
static void Main(string[] args)
{
string[] playerNames = new string[100];
int[] playerScores = new int [100];
int numPlayers = 0;
double averageScore;
DisplayData(playerNames);
}
static void InputData(string[] playerNames, int[] playerScores, ref int numPlayers)
{
string playerName;
do
{
int i = 0;
Console.WriteLine("Enter the name of the player...Enter \"Q to exit...");
playerName = Console.ReadLine();
if (playerName == "Q" || playerName == "q")
Console.WriteLine("No further user input needed...\n");
else
playerNames[i] = playerName;
Console.WriteLine("Enter the score of the player...");
int playerScore = Convert.ToInt32(Console.ReadLine());
playerScores[i] = playerScore;
numPlayers += i;
i++;
}
while (playerName != "Q");
}
static void CalculateAverageScore(int[] playerScores, ref int averageScore)
{
InputData(playerScores);
InputData(ref numPlayers);
int averageScores = 0;
averageScores = playerScores / numPlayers;
}
The biggest question I have is that I cannot seem to pass the array data. I am plagued by "No overload method for "Input Data" or whatever method I am using. So I'm curious as to how I can pass the array data to another method.
Since this is homework, I won't give you the full answer, but here is a way forward.
Instead of using the ref keyword, just pass the array into the method. Have the method return an int instead of void. Calculate the average within the method and have the final line of the method return the int that you've calculated
static int CalculateAverageScore(int[] playerScores)
{
// calculate average
return average; // the int you've calculated.
}
Call the method from the main, when you need to acquire the average.
Also, are you missing some braces { } for the 6 lines that come after your else statement?

Array correlation issues

I am trying to create an application that prompts a user for 5 names, then display each name and allow the user to enter a score for that particular name. So if in the first array, the value for index [0] is a string "Bob", then in the other array for scores index [0] should be the score for bob.
I am having a hard time understand how to pass the nameArray[] to the PopulateScore() method so that it can display the name for the user to enter a corresponding score.
I also have to search the Array by name and return the score.
Thanks for any help.
public class InitArraya
{
public static string[] arrayName = new string[5];
public static int[] arrayScore = new int[5];
public static void PopulateNameArray()
{
// Prompt user for names and assign values to the elements of the array
for (int intCounter = 1; intCounter < arrayName.Length; intCounter++)
{
Console.Write("Enter name {0}: ", intCounter);
arrayName[intCounter] = Console.ReadLine();
}
}
public static void PopulateScoreArray(string[] array)
{
// Prompt user for names and assign values to the elements of the array
for (int intCounter = 1; intCounter < 5; intCounter++)
{
Console.Write("Enter score for {0}: ", arrayName[0]);
arrayScore[intCounter] = Convert.ToInt32(Console.ReadLine());
}
}
public static void Main( string[] args )
{
Console.WriteLine("Enter 5 names:"); // headings
PopulateNameArray();
PopulateScoreArray(arrayName);
Console.ReadLine();
}
}
Make array of objects which contains the name and score, this will make your solution much more usefull and readable.
public class NameScore{
public string Name { get; set; }
public int Score { get; set; }
}
public class InitArraya{
public NameScore[] arrayScore = new NameScore[5];
...
public static void PopulateScoreArray(string[] array)
{
// Prompt user for names and assign values to the elements of the array
for (int intCounter = 0; intCounter < array.Length; intCounter++)
{
Console.Write("Enter score for {0}: ", array[intCounter]);
arrayScore[intCounter] = Convert.ToInt32(Console.ReadLine());
}
}
Assuming that there are always 5 names in arrayName. Extra checks should be made otherwise.
Oh, and start intCounter at 0 in PopulateNameArray too.
in
public static void PopulateScoreArray(string[] array)
change
Console.Write("Enter score for {0}: ", arrayName[0]);
to
Console.Write("Enter score for {0}: ", array[intCounter]);
To use input array. Also in all for(-) change the start for counter to 0
for (int intCounter = 0; intCounter < 5; intCounter++)

Categories

Resources