I am looking to find a way to take assign the value of user inputs to the variables I have, but to use a loop to take this entry and position it on the screen. Is there a way to do this?
Below is my non-working code but hopefully it should provide an idea of what I am trying to achieve.
public void StudentDetailInput()
{
const int startpoint = 2;
string[] takeinput = new string[] {FirstName, Surname, MiddleName, StudentId, Subject, AddressLine1, AddressLine2, Town, Postcode, Telephone, Email };
for (int x = 0; x < takeinput.Length; x++)
{
Console.SetCursorPosition(30, startpoint + x);
[x] = Console.ReadLine();
}
}
You might want to use a Dictionary:
private Dictionary<string, string> _answers = new Dictionary<string, string>();
public void StudentDetailInput()
{
string[] takeinput = new string[] {
"FirstName",
"Surname",
"MiddleName",
"StudentId",
"Subject",
"AddressLine1",
"AddressLine2",
"Town",
"Postcode",
"Telephone",
"Email"
};
_answers.Clear();
for (int x = 0; x < takeinput.Length; x++)
{
Console.Write(takeinput[x] + ": ");
var answer = Console.ReadLine();
_answers.Add(takeinput[x], answer);
}
}
So you can display the answers like this:
for(var i = 0; i < _answers.Count; i++)
{
Console.WriteLine("{0}: {1}", _answers.Keys[i], _answers.Values[i]);
}
If your concern is that you do not want to use this many lines on the console you could keep track of the length of the answers and try to put the cursor right behind the answers so far. The problem with this is that you'll need to take the screen's width (which can be adjusted by the user) into account to calculate the correct line and position.
Another issue with this construction will be that users will expect the cursor to go one line down (that is what enter does) so the user experience might suffer.
An alternative would be to clear the screen after each input, display all answers so far starting at line 2 of the console and positioning the next question on line one:
for (int x = 0; x < takeinput.Length; x++)
{
Console.Clear();
for(y = 0; y < x; y++)
{
Console.SetCursorPosition(0, y + 1);
Console.WriteLine("{0}: {1}", _answers.Keys[y], _answers.Values[y]);
}
Console.SetCursorPosition(0, 0);
Console.Write(takeinput[x] + ": ");
var answer = Console.ReadLine();
_answers.Add(takeinput[x], answer);
}
This might go horribly wrong when the number of questions is more than the number of lines on the console.
Your string array definition is not clear, but I think you are looking for something like this:
public void StudentDetailInput()
{
const int startpoint = 2;
string[] takeinput = new string[11];
for (int x = 0; x < takeinput.Length; x++)
{
Console.SetCursorPosition(30, startpoint + x);
takeinput[x] = Console.ReadLine();
}
}
Now
// FirstName = takeinput[0]
// Surname = takeinput[1]
// ...
This line is wrong.
[x] = Console.ReadLine();
If you want to assign to your elements of array, what you read with ReadLine() method, you should use
takeinput[x] = Console.ReadLine();
If you just want to assign the counter what you read, you should use;
x = Convert.Int32(Console.ReadLine());
EDIT: If I understand your question clearly, you just want to this;
List<string> list = new List<string>();
string input = "";
do
{
input = Console.ReadLine();
list.Add(input);
}
while (input != "exit");
list.Remove("exit");
foreach (var item in list)
{
Console.WriteLine(item);
}
Related
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.
I'm a relatively new student to C# programming and I'm having a lot of trouble with 2-D arrays. In this program the user is supposed to input names, verbs, and objects for an insult generator, but the problem is that I have to pointlessly store them all in one 2-D string array and generate the insults in a 1-D string array and I'm just completely lost. Can I store name, verb, and object into a single 2-D string array? Any help would be appreciated.
My issue is with initializing and storing the 2D string array and then converting to the 1D array.
private static void Generate(int insultnum, int sentnum)
{
int Ncounter = 1;
int Vcounter = 1;
int Ocounter = 1;
string[,] name = new string[sentnum,?];
string[,] verb = new string[sentnum,?];
string[,] insult = new string[sentnum,?];
do
{
Console.Write("Please enter name of #{0}: ", Ncounter);
//length and height 2D array for loop text is just a placeholder from an earlier project
for (int i = 0; i < length; i++)
{
for (int j = 0; j < height; j++)
{
name[Ncounter - 1, ??] = Console.ReadLine();
}
}
//
Ncounter++;
} while (Ncounter < sentnum);
do
{
Console.Write("Please enter name of #{0}: ", Vcounter);
verb[Vcounter-1, ?] = Console.ReadLine();
//2D array loop text
Vcounter++;
} while (Vcounter < sentnum);
do
{
Console.Write("Please enter name of #{0}: ", Ocounter);
insult[Ocounter-1, ?] = Console.ReadLine();
//2D array loop text
Ocounter++;
} while (Ocounter < sentnum);
Ncounter = 0;
Vcounter = 0;
Ocounter = 0;
string[] insults = new string[insultnum];
//insults = name[?,?] + " " + verb[?,?] + " " + object[?,?];
}
Example Output:
Enter the number of insults to generate: 3
Enter the number of names, verbs, and objects: 3
Please enter name #1: Bob
Please enter name #2: Rhys
Please enter name #3: Kaa
Please enter verb #1: licks
Please enter verb #2: touches
Please enter verb #3: tastes
Please enter object #1: dirt
Please enter object #2: cars
Please enter object #3: asphalt
Insults have been generated
Kaa licks dirt
Bob tastes asphalt
Bob licks cars
2D array i.e. string[,] is a bit strange collection to store the data, since it requires that
NameCounter == VerbCounter == ObjectCounter
More natural choice is a jagged array string[][] which allows arbitrary NameCounter, VerbCounter, ObjectCounter. And, please, decompose your solution, split it to number of easy to implement and test methods:
// Random generator for insulting
private Random rgen = new Random();
// 1st index - category (name/verb/insult), 2nd index item within category
private static string[,] data;
private static string[] categories = new string[] {
"name", "verb", "insult",
};
// Input single categore, e.g. Names or Verbs
private static void InputCategory(int category) {
for (int i = 0; i < data.GetLength(1); ++i) {
Console.Write($"Please enter {categories[category]} #{i + 1}: ");
data[category, i] = Console.ReadLine();
}
}
// Input all categories
private static void InputData() {
Console.Write($"Enter the number of names, verbs, and objects: ");
// simplest; more accurate implementation uses int.TryParse()
int n = int.Parse(Console.ReadLine());
data = new string[categories.Length, n];
foreach(var int i = 0; i < categories.Length; ++i)
InputCategory();
}
To write an insult generator you should combine random items from each category
private static string[] Insults(int count) {
string[] result = new string[count];
// take count times a item from each category
for (int i = 0; i < count; ++i) {
StringBuilder sb = new StringBuilder
for (int c = 0; c < categories.Length; ++c) {
if (c > 0)
sb.Append(' ');
sb.Append(data[c, rgen.Next(data.GetLength(1))]);
}
result[i] = sb.ToString();
}
return ressult;
}
Having these methods you can put easily
private static void Main() {
int numberOfInsults = ....
InputData();
foreach (var insult in Insults(numberOfInsults))
Console.Write(insult);
...
}
I have been trying to do a task I recieved a few days earlier. Basically the task is a console application in C# :
Prompt the user for input of 2 coordinates in untill the word "stop" is entered. Once the word "stop" is hit, print a "*"(star char) at each of the input coordinates. The field where the coordinates are printed is 20x20. I have tried doing this, but to no avail. If somebody could help me out and show me how to store the input x,y into a 2d array, that'd be great :)
How the application should work : http://imgur.com/a/SnC1k
The [0,5] [18,18]etc are the entered coordinates which are later on printed down below. The "#" chars dont need to be printed , they are here only to help with the understanding of the task.
How I tried to do it but DIDN'T work :
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
bool stopped = false;
int x=0;
int y=0;
while (stopped)
{
string[,] coordinates = Console.ReadLine();
string response = Console.ReadLine();
response = response.ToLower();
if (response == "STOP")
stopped = true;
else
{
string[] xy = coordinates.Split(',');
x = int.Parse(xy[0]);
y = int.Parse(xy[1]);
Console.SetCursorPosition(x, y);
Console.Write("*");
}
}
}
}
}
The code I did just doesn't do it. It shows multiple errors that I do not know how to fix and the only thing I was able to do is get it to print a char immediately when I enter the first coordinates, instead of printing a char at every entered coordinate, AFTER the word STOP is hit.
Create a 20x20 2d array. Prompt the user for the x and y. Once you have each store a 1 in your array[x,y] once the user hits stop loop through the array and print '#' if null or 0 and print '*' if its a 1.
Edit, something along these lines I didn't check if this works or compiles but should get you on the right track.
int[,] grid = new int[20,20];
while (!stopped)
{
string[,] coordinates = Console.ReadLine();
string response = Console.ReadLine();
response = response.ToUpper();
if (response == "STOP")
stopped = true;
else
{
string[] xy = coordinates.Split(',');
x = int.Parse(xy[0]);
y = int.Parse(xy[1]);
grid[x,y] = 1;
}
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 20; j++)
{
if (grid[i, j] > 0)
Console.Write("*");
else
Console.Write("#");
}
Console.WriteLine("");
}
}
As you only need to display a matrix-style output you don't need to use Console.SetCursorPosition(x, y);
Also you should read the user input somehow and set the proper value for the given position instead of store the coordinates.
Try this and let me know how this works for you. You can see it also on this fiddle. Enter the coordinates as two space-separated numbers and enter stop to print.
using System;
public class Program
{
public static void Main(string[] args)
{
int x=0;
int y=0;
char[,] coordinates = new char[20,20];
while (true)
{
//user must enter 2 3 for example.
string[] response = Console.ReadLine().Split(new[]{" "}, StringSplitOptions.RemoveEmptyEntries);
if (response[0].ToLower() == "stop")
break;
x = int.Parse(response[0]);
y = int.Parse(response[1]);
coordinates[x,y] = '*';
}
//Print the output
for(var i = 0; i < 20; i++)
{
for( var j = 0; j < 20; j++)
if (coordinates[i,j] == (char)0)
Console.Write('#');
else
Console.Write(coordinates[i,j]);
Console.WriteLine();
}
}
}
Hope this helps!
I suggest decomposing the task, cramming entire rountine into a single Main as bad practice; you should:
- ask user to enter coordinates
- print out the map
Let's extract the methods:
private static List<Tuple<int, int>> s_Points = new List<Tuple<int, int>>();
private static void UserInput() {
while (true) {
string input = Console.ReadLine().Trim(); // be nice, let " stop " be accepted
if (string.Equals(input, "stop", StringComparison.OrdinalIgnoreCase))
return;
// let be nice to user: allow he/she to enter a point as 1,2 or 3 4 or 5 ; 7 etc.
string[] xy = input.Split(new char[] { ',', ' ', ';', '\t' },
StringSplitOptions.RemoveEmptyEntries);
int x = 0, y = 0;
if (xy.Length == 2 && int.TryParse(xy[0], out x) && int.TryParse(xy[1], out y))
s_Points.Add(new Tuple<int, int>(x, y));
else
Console.WriteLine($"{input} is not a valid 2D point.");
}
}
Printing out
private static void PrintMap(int size = 20) {
// initial empty map; I prefer using Linq for that,
// you can well rewrite it with good old for loops
char[][] map = Enumerable.Range(0, size)
.Select(i => Enumerable.Range(0, size)
.Select(j => '#')
.ToArray())
.ToArray();
// fill map with points;
// please, notice that we must not print points like (-1;3) or (4;100)
foreach (var point in s_Points)
if (point.Item1 >= 0 && point.Item1 < map.Length &&
point.Item2 >= 0 && point.Item2 < map[point.Item1].Length)
map[point.Item1][point.Item2] = '*';
// The string we want to output;
// once again, I prefer Linq solution, but for loop are nice as well
string report = string.Join(Environment.NewLine, map
.Select(line => string.Concat(line)));
Console.Write(report);
}
Finally, all you have to do it to call the methods:
static void Main(string[] args) {
UserInput();
PrintMap();
Console.ReadKey();
}
I have a list of incomplete band names such as
string band1 = "ONE ...", string band2 = "... 5", string band3 = "30 ... ... ...", string band4 = "The ... Stones"
I need to replace the characters ... to form the full band's name so they become
ONE DIRECTION, MAROON 5, 30 SECONDS TO MARS, THE ROLLING STONES
I have the associated answer, for example the string DIRECTION that can be combined with string band1 = ONE ... to form ONE DIRECTION. My question is since the ... characters may be located before or after the string ONE, how can I make sure to create ONE DIRECTION instead of DIRECTION ONE and so on?
use a combination of string.StartsWith, string.EndsWith and string.Length to determine the correct replacement
Try this example with your sample strings. You will the get the idea.
static void Main(string[] args)
{
string question = string.Empty;
string answer = string.Empty;
string formattedString = string.Empty;
question = Console.ReadLine();
Console.WriteLine("Replace ... with:");
answer = Console.ReadLine();
formattedString = question.Replace("... ", answer);
Console.WriteLine(formattedString);
Console.ReadLine();
}
EDIT 2:
In this solution, i'm splitting your string by ... to an array of strings. Like this you know where ... are placed at, no matter how many of them are around and where they are and finally merge them.
Additionally i'm working with a Dictionary, with this it's dynamic.
Have a look at the code:
static void Main(string[] args)
{
Dictionary<string, string> bands = new Dictionary<string, string>();
bands.Add("30 ... ... ...", "SECONDS TO MARS");
bands.Add("... 5", "MAROON");
bands.Add("... STEPS ... ...", "TWO FROM HELL");
foreach (KeyValuePair<string, string> band in bands)
{
bool solved = false;
while (!solved)
{
Console.WriteLine("current band: " + band.Key);
string input = Console.ReadLine();
if (band.Value == input.ToUpper())
{
Console.WriteLine("correct");
string[] splittedQuestion = band.Key.Split(new string[] { "..." }, StringSplitOptions.None);
string[] splittedAnswer = band.Value.Split(' ');
// fill splittedQuestion string with answer values
for (int i = 0; i < splittedAnswer.Count(); i++)
{
int currentIndex = GetNextDotIndex(splittedQuestion);
if (currentIndex != -1)
{
splittedQuestion[currentIndex] = splittedAnswer[i];
}
}
// build result
string result = "";
for (int i = 0; i < splittedQuestion.Count(); i++)
{
result += splittedQuestion[i].Trim().ToUpper();
if (i < splittedQuestion.Count() - 1)
{
result += " ";
}
}
Console.WriteLine(result);
solved = true;
}
else
{
Console.WriteLine("wrong");
}
}
}
Console.WriteLine("finished");
Console.ReadLine();
}
private static int GetNextDotIndex(string[] splittedQuestion)
{
for (int j = 0; j < splittedQuestion.Count(); j++)
{
if (splittedQuestion[j] == "" || splittedQuestion[j] == " ")
{
return j;
}
}
// return -1, when no more ... are available
return -1;
}
Everything I have runs fine, but I am looking for a way to prompt the user if duplicate order number is entered and have them reenter a new order number. Right now it just accepts duplicates and does not display the error message I wanted. I created two classes Order the base, and ShippedOrder. Here is the equals method I have within the Order class.
public override bool Equals(Object e)
{
bool equal;
Order temp = (Order)e;
if (orderNumber == temp.orderNumber)
equal = true;
else
equal = false;
return equal;
Here is what I have within the main method. I can post everything if it would help. Again I am looking for help finding a way to prevent the user form imputing the same two order numbers.
static void Main(string[] args)
{
double sum = 0;
ShippedOrder[] orderArray = new ShippedOrder[5];
ShippedOrder[] check = new ShippedOrder[5];
bool wrong = true;
for (int x = 0; x < orderArray.Length; ++x)
{
orderArray[x] = new ShippedOrder();
Console.Write("Enter order number: ");
orderArray[x].orderNumber = Convert.ToInt32(Console.ReadLine());
for (int y = 0; y < x; ++y)
{
check[y] = new ShippedOrder();
if (orderArray[x].Equals(check[y]))
wrong = false;
while (!wrong)
{
Console.WriteLine("Sorry, the order number {0} is a duplicate. \nPlease reenter {1}",
orderArray[x], check[y]);
for (y = 0; y < x; ++y)
{
if (orderArray[x].Equals(check[y]))
wrong = false;
}
check[y] = orderArray[x];
}
}
Console.Write("Enter cusomer name: ");
orderArray[x].customerName = Console.ReadLine();
Console.Write("Enter quanity: ");
orderArray[x].quanityOrdered = Convert.ToInt32(Console.ReadLine());
I would do this with LINQ, this is where it actually shines (if this code is not called thousand times per second)
var arrayExpectedCount = 5;
var orderArray = new List<ShippedOrder>(); //define array of orders to generate
var check = new List<ShippedOrder>(); //array of orders already shipped,already present
......
//infinit interation
while(true) {
var orderNumber = Convert.ToInt32(Console.ReadLine());
if(!check.Exist(o=>o.orderNumber == orderNumber)
{
//create a new order and push it to the orderArray
}
//break condition of the infinit loop
if(orderArray.Count == arrayExpectedCount)
break;
}
If this is not what you're asking for, please clarify.
List<ShippedOrder> orderArray = new List<ShippedOrder>();
do {
int newOrderNum = 0;
// Retrieve first attempt
Console.Write("Enter order number: ");
newOrderNUm = Conver.ToInt32(ConsoleReadLine());
// Check if any of the orders in orderArray have the same order number
while(orderArray.Any(a=>a.orderNumber == newOrderNum) {
Console.Write("Sorry, the order number is a duplicate. Please enter re-enter the order number: ");
newOrderNum = Conver.ToInt32(ConsoleReadLine());
};
orderArray.Add(new ShippedOrder() {
orderNumber = newOrderNum,
};
} while(orderArray.Length < 5);