How to link user input from a string and int - c#

I want to create an application where the user can enter items and the price, then show the most expensive and the cheapest item.
I'm totally new to C# and have no programming experience of any language, started to learn 2,5 weeks ago. I don't understand how I can link the item with the price and then do the calculation. The penny hasn't dropped yet in terms of how I can build an application :(
ItemInput();
PricingInput();
}
private static void ItemInput()
{
Console.WriteLine("Add your items and price, once you're done, type 'end' ");
AskForTheItem();
AskForThePrice();
}
static void AskForTheItem()
{
while (itemPrice != "end")
{
Console.Write("Add your item:");
string item = Console.ReadLine();
Console.Write("Add the price:");
int price = int.Parse(Console.ReadLine());
itemPrice = Console.ReadLine();
}
Console.WriteLine("Add your item: ");
name = Console.ReadLine();
numberOfItems++;
}
static void AskForThePrice()
{
Console.WriteLine("Add the price: ");
price = int.Parse(Console.ReadLine());
numberOfPrice++;
}
private static void PricingInput()
{
Console.WriteLine($"The cheapest item is: {name} and the most expensive item is: {name} ");

private static void ItemInput()
{
PricingInput(AskForTheItem());
}
static Dictionary<String, int> AskForTheItem()
{
var result = new Dictionary<String, int>();
Console.WriteLine("Add your items and price, once you're done, type empty item ");
while (1)
{
Console.Write("Add your item or keep empty :");
string item = Console.ReadLine();
if(String.IsNullOrEmpty(item)) return result;
Console.Write("Add the price:");
while(!int.TryParse(out var price, Console.ReadLine()) Console.Write("Wrong price, please Add the price:");
result.Add(item, price);
}
}
private static void PricingInput(Dictionary<String,int> list)
{
String minItem = null;
int minPrice = -1;
String maxItem = null;
int maxPrice = -1;
foreach(var i in list) {
if(price<0 || i.Value<price) { minItem = i.Key; minPrice=i.Value;}
if( i.Value>price) { maxItem = i.Key; maxPrice=i.Value;}
Console.WriteLine($"The cheapest item is: {1} and the most expensive item is: {2} ",minItem,maxItem); }

Welcome to StackOverflow! Your question seems to be pretty broad but I think what you'd need is some first steps into object-oriented programming with classes.
Your code seems like a good start but for storing the information you'll need some objects.
You can create your own objects using a class. In this case you class would need a property for its name and one for it's price.
Defining the class would be as follows (you should do that in a new file):
class MyItem{
public string Name { get; set; }
public int Price { get; set; }
}
Then at the start of the class with the AskForTheItems method and probably also the Main method, you need to add a List to store the items. You'd do that like this:
private static List<MyItem> items = new List<MyItem>();
For the method which gets the items, you'll need to some adjustments. You also don't need the numberOfItems-variable anymore since you can just call items.Count if you need it.
private static void AskForTheItems()
{
do
{
Console.WriteLine("Add your item:");
// get the name
Console.Write("Name: ");
string name = Console.ReadLine();
// get and convert the price
Console.Write("Price: ");
int price = int.Parse(Console.ReadLine());
// create the item and fill it with the values
MyItem item = new MyItem();
item.Name = name;
item.Price = price;
// add the item to your list
items.Add(item);
// ask if the user want's to add another one
Console.WriteLine("Again? (y/n)");
}
while (Console.ReadKey(true).Key != ConsoleKey.N);
}
Printing the cheapest and most expensive one is fairly easy using Linq (there might even be an easier/better way).
private static void PrintCheapestAndMostExpensive() {
// get the first item where the price is the same as the minimum of all prices in the list
MyItem cheapestItem = items.First(i => i.Price == items.Min(i2 => i2.Price));
// get the first item where the price is the same as the maximum of all prices in the list
MyItem mostExpensiveItem = items.First(i => i.Price == items.Max(i2 => i2.Price));
Console.WriteLine($"The cheapest item is: {cheapestItem.Name} and the most expensive item is: {mostExpensiveItem.Name}");
}
I hope this helps. If you have any questions, feel free to ask - I'll try to explain anything you don't understand yet.
By the way there a are few things I didn't do/cover because I feel like it'd be a bit too much to explain for a small program like this. Currently there is no error handling when converting the input-string to an int (bad). There are also easier ways to write the initialisation for the item but I figured this way it's easier to understand.
Also with this code it always prints the first item which has the lowest price. If there are two which both have the lowest price, this might be a problem.
Linq itself is fairly hard (but very very important), that's why I would strongly reccomend you to read something about it. I'd happily explain the Linq I used here with more detail but since it's such a huge topic, I won't cover much more.

Related

Using a sequencing variable to name a record?

I would like to use my variable i (that is used to sequence a loop) to name a record. This in order to know both how many of these records I have and to be able to loop through each one in a for loop.
This is how I have tried to do it:
while (UserValue != "none")
{
Console.WriteLine("Input a product Name or type \"none\" to exit.");
UserValue = Console.ReadLine();
if (UserValue == "none")
break;
Console.WriteLine("Input this products value in Pounds.");
products i = new(UserValue, float.Parse(Console.ReadLine()));
i = i + 1;
}
I'm not even sure if it is possible so if it isn't, any alternative solution would be greatly appreciated.
It seems, that you want a collection, say List<T> of items, e.g.
//TODO: decimal is better if "value" stands for money
// I used named tuple here, but you may want an elaborated custom class
var products = new List<(string name, float value)>();
// Keep asking user to input products until "none" is given
while (true) {
Console.WriteLine("Input a product Name or type \"none\" to exit.");
UserValue = Console.ReadLine();
//TODO: trim spaces and, probably, use case insensitive check
if (UserValue == "none")
break;
Console.WriteLine("Input this products value in Pounds.");
//TODO: float.TryParse is a better option
products.Add((UserValue, float.Parse(Console.ReadLine())));
}
then having collection you can loop over it:
for (int i = 0; i < products.Count; ++i) {
(string name, float value) = products[i];
...
}
or
foreach (var (name, value) in products) {
...
}
A better strategy is using a List<products>. Also, rename the products class to just product:
var allProducts = new List<product>();
// ...
Console.WriteLine("Input a product Name or type \"none\" to exit.");
UserValue = Console.ReadLine();
if (UserValue == "none")
break;
Console.WriteLine("Input this product's value in Pounds.");
allProducts.Add(new product(UserValue, float.Parse(Console.ReadLine())));
You can still loop over this allProducts list with either a for loop (look at the .Count property of the list) or a foreach loop.

How can I save user input in another method and still keep it on return to the method again

Newbie here learning c#. I have a question regarding saving user input.
I have two methods, main and the car method. In the car method i have a list with three cars already in it. While in the car method the user can choose to add a new car to the list or print out all cars in that list.
When adding a new car and after choosing to print out the list, the program shows all the cars including the newly added one.
But on returning to the menu in main method and then entering the car method again, the list is reset to only hold the three cars that is put in the list from start. Is there a way to actually save the input from user, store it in a list or something else and then be able to access it to print it out? As mentioned, I'm a total beginner here so i hope I'm making sense and really would appriciate all feedback and tips! Thank you.
using System;
using System.Collections.Generic;
class Program{
public static void Main(string [] args){
int menuSelect = 0;
do{
// Printing menu options and taking user input
Console.WriteLine("1. Cars " + "\n2. Exit");
Console.WriteLine("Enter a option: ");
menuSelect = Convert.ToInt32(Console.ReadLine());
// Go to Cars method
if(menuSelect == 1){
Cars();
// Message to user if input is higher than menu allows
} else if (menuSelect > 2){
Console.WriteLine("\nInvalid Choise");
}
}while(menuSelect != 2);
Console.WriteLine("\nPress 'Enter' to exit...");
Console.ReadLine();
}
public static void Cars(){
// List containing cars. Resets every time entering the method to
// just BMW, Volvo and Fiat. Regardless if the user has added a new car.
List <string> carList = new List <string> {"BMW", "Volvo", "Fiat"};
int carMenuSelect = 0;
do{
// Printing menu and taking user input
Console.WriteLine("1. Add Car" + "\n2. Show Cars" + "\n3. Exit");
Console.WriteLine("Enter a option: ");
carMenuSelect = Convert.ToInt32(Console.ReadLine());
// Lets the user add a new car to the list
if (carMenuSelect == 1){
Console.WriteLine("Enter new car: ");
string newCar = Console.ReadLine();
Console.WriteLine("New Car Added!");
carList.Add(newCar);
} else if(carMenuSelect == 2){
foreach (string car in carList){
Console.WriteLine(car);
}
} else if(carMenuSelect > 3){
Console.WriteLine("\nInvalid option...");
}
}while(carMenuSelect != 3);
Console.WriteLine("Press 'Enter' to return to menu....");
Console.ReadLine();
}
}
the func Car creates a new list each time it is called, so you should create a list in the main func and send it to the function by ref to add items to it. Code:
public static void Main(string [] args){
List <string> carList = new List <string> {"BMW", "Volvo", "Fiat"};
Car(carList);
}
public static void Cars(ref List<string> myList){
myList.Add("new Car");
}
or Your cand send the list then return the modified list and save it in the original one.
Code:
public static void Main(string [] args){
List <string> carList = new List <string> {"BMW", "Volvo", "Fiat"};
carList = Car(carList);
}
public static List<string> Cars(List<string> myList){
myList.Add("new Car");
return myList;
}

Compare ListBox and list then print to Label

I am using a ListBox that stores items such as camping gear. The ListBox will have tent, camping chairs, coffee and so on.
Then I created a list that has the prices for each item called lstprices.
When I double click on the entry it will appear in another ListBox while pulling the price from the lstprices and add it to a subtotal Label.
try
{
if (lstItems.Items.Count > 0)
{
lstOrder.Items.Add(lstItems.SelectedItem.ToString());
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
I am assuming I would somehow add information to the lstOrder.Items since I know the element numbers but don't understand how to display it in my Label.
I hope this makes sense.
Also for this statement:
decimal STotal = decimal.Parse(lblSubtotal.Text.ToString());
it errors stating that its in the wrong format when I double click the item.
Sorry i cannot comment so have to post an answer:
if you have to keep track of multiple properties of an object then you should create a class of it for example (Object Oriented Programming):
public class Product
{
public string Name {get;set;}
public double Price {get;set;}
public Product(string name, double price)
{
Name = name;
Price = price
}
}
this way you can just do: Product chair = new Product("Camping Chair", 12.99);
or you can fill a list
List<Product> products = new List<Product>()
{
new Product("Camping Chair", 12.99),
new Product("Tent", 25.99)
}
and then display your products in a list or datagridview etc. it will be a better approach then maintaining two lists with names and prices.
this will also make work with the listbox easier it has a property called SelectedItem which you can cast to your class and then reference it properties for example:
Product selectedProduct = myListbox.SelectedItem as Product;
myLabel.Text = selectedProduct?.Price.ToString();
EDIT:
since classes have not been covered by, what you can do is use a Dictionary<string,double> to keep track of your prices and keys (product name) or at least a List<KeyValuePair<string,double>> :
Below a quick example to get you started:
Dictionary<string, double> products = new Dictionary<string, double>()
{
{"Camping Chair",33.0},
{"Stool",12.99},
};
//accessing the price via the key, which
var price = products.Where(x => x.Key == "Stool").SingleOrDefault();
// you could then pass in the selected item of your list box as string
var price = products.Where(x => x.Key == listbox.SelectedItem.ToString()).SingleOrDefault();
More about dictionary at msdn
More about KeyValuePair at msdn

how do you create a loop that cycles through more than one List in C#

I do not want the answer, I would just like how to go about this or some examples please !
Requirements
Create a custom method called CombineTheLists and use the 2 lists you
created as arguments in the function call.
i. This method should have 2 parameters and catch the incoming Lists.
ii. It should not return anything.
iii. Inside of the function, create a loop that cycles through both
lists at the same time.
iv. Each time the loop runs, pull an item from the 1st List and the
matching price from the 2nd List and combine them into one text string
using the format of “The X costs $Y.” Where X is the item to be bought
and Y is a the cost of the item. Make sure to use a $ and format to 2
decimal places
My Current Code
enter code class Program
{
static void Main(string[] args)
{
// list for items
List<string> items = new List<string>() {
"laptop", "book", "backpack", "cellphone", "pencils", "notebook", "pens" };
// list for prices
List<double> prices = new List<double>() {
900.54, 40.20, 21.00, 600.00, 4.25, 10.50, 5.00 };
}
}
public static void CombineTheLists( string item, double prices)
{
for (int i = 0; i < item.Length; i++)
{
}
}
}
It seems, that you are looking for Zip:
var data = items
.Zip(prices, (item, price) => new {
item,
price });
...
foreach (var value in data) {
// value.item for item
// value.price for price
}
Edit: In case of good old for loop:
namespace MySolution {
class Program {
static void Main(string[] args) {
...
CombineTheLists(items, prices);
}
public static void CombineTheLists(List<string> items, List<double> prices) {
for (int i = 0; i < Math.Min(items.Count, prices.Count); ++i)
Console.WriteLine($"item {items[i]} costs {prices[i]:f2}"); // f2 - format string
}
}
}
You are on (one of) the right tracks, but first, you should change your method declaration to accept two lists, instead of a string and double:
public static void CombineTheLists(List<string> items, List<double> prices)
{
for (int i = 0; i < items.Count; i++)
{
}
}
You already have written a for loop with the looping variable i. As you know, i will increase every iteration. This means that items[i] will be the corresponding item in that iteration and prices[i] will be the corresponding price. For example, here's some code to print the item and price on one line:
// in the for loop
Console.WriteLine($"{items[i]} - {prices[i]}");
// try to do the formatting to 2 d.p. yourself
Why dont you create a object with two attributes and a list of objects?
class item {
String name;
String price;
/*getter and setters*/
}
class main {
public static void CombineTheLists()
{
List<item> items = new List<item>() { item1, item2, item3,.... };
}
}

Checking for double booking in arrays

Ok, my project to create an event organizer for a music contest. Basically I take input data such as a list of about 400 entries and I output into a few separate excel sheets by room number and type. The problem is, when assigning events to an array, (I have a separate array for each room and all the arrays are contained in a list) I need to check and fix if accompanists are double booked for the same time slot. Or essentially, if two different arrays have the same accompanist value for array[i]
Ideas? Please try to explain well, I'm self taught with only a bit of experience
private void assignEvents()
{
// assign every event in order
// check accompanists for no double-books
foreach (Event[] room in roomList)
{
int i = 0;
foreach (Event ev in eventList)
{
if (ev.Type == room[0].Type)
{
room[i] = ev;
i++;
}
}
}
You could do it with LINQ like Tejs suggests, but I would go another route since you are designing an organizer and you will probably need the extra information any way (for example, to display the schedule of an accompanist). I would have a list of all accompanists with a sorted array of all of their bookings (basically , their schedule). You can then have a function to check for every new booking whether there is a conflict (in the booking array) for each of the accompanists in the booking and if not, continue by adding the booking to the accompanists' schedule
If I understand you correctly, you must compare values per column. I suggest to create your own RoomList collection class by deriving it from your actual collection type and to add it the possibility to iterate columns
public class RoomList : List<Event[]>
{
public IEnumerable<Event> TimeSlot(int columnIndex)
{
foreach (Event[] events in this) {
if (events != null && columnIndex < events.Length) {
yield return events[columnIndex];
}
}
}
}
Then you can use LINQ to get double bookings
RoomList roomList = new RoomList();
// ...
for (int slot = 0; slot < roomList[0].Length; slot++) {
var doubleBooked = roomList.TimeSlot(slot)
.GroupBy(e => e.Type)
.Where(g => g.Count() > 1);
if (doubleBooked.Any()) {
Console.WriteLine("Doubly booked accompanists in slot {0}", slot);
foreach (var accompanistGroup in doubleBooked) {
Console.WriteLine(" {0}", accompanistGroup.Key);
}
}
}

Categories