Search specific element in list from user input - c#

I have a list that contains elements. The user should be able to search for specific element and the list. Then list should print out all lines that contains this specific element. Why is this not working?
Car search = new Car();
public void SearchLog()
{
for (int i = 0; i < myList.Count; i++)
{
if (myList[i].Model== search.Model)
{
Console.WriteLine("Model :" + search.Model)
}
}
}
Console.Write("Search for model:");
search.searchModel = Console.ReadLine();
It's working now! Always something new to learn. The issue was my class variable. So I used variable from same scope instead.

I have complete code for you based on the information from the question and comments:
This will be the sample class for Car;
class Car
{
public string Model { get; set; }
public string Name { get; set; }
public string Brand { get; set; }
//Rest of properties here
public override string ToString()
{
string output = String.Format("Model :{0} \n Name :{1} \n Brand :{2}", this.Model, this.Name, this.Brand);
return output;
}
}
Here is the main function that do the operations:
public static List<Car> myList = new List<Car>();
static void Main(string[] args)
{
myList.Add(new Car() { Model = "A", Name = "XXX", Brand = "Some Brand" });
myList.Add(new Car() { Model = "B", Name = "YYY", Brand = "Some Brand1" });
myList.Add(new Car() { Model = "C", Name = "ZZZ", Brand = "Some Brand2" });
Car search = new Car();
Console.Write("Search for model:");
search.Model = Console.ReadLine();
Console.WriteLine("Following Result Found for {0}", search.Model);
SearchLog(search);
}
Finally the signature for SearchLog is:
public static void SearchLog(Car search)
{
var resultList = myList.Where(x => x.Model == search.Model).ToList();
int i = 1;
foreach (var car in resultList)
{
Console.WriteLine("Result {0} : {1}", i++, myList[i].ToString());
}
}
I have another suggestion; The search need not be an object of the class Car It can be a string instead;
You can try it in your own way like the following:
Console.Write("Search for model:");
string inputSearch = Console.ReadLine();
bool carFound = false;
for (int i = 0; i < myList.Count; i++)
{
if (myList[i].Model == inputSearch)
{
Console.WriteLine("Model: " + myList[i].Model);
carFound = true;
}
}
if (!carFound) { Console.WriteLine("None model were found"); }

Related

Sorting through a 2D array for a specific element in C#

I'm trying to sort through a 2d list in C#. I have code written that lets me create a list from data pulled from a CSV file, however I'm stuck on the function to sort them.
The list details the shop ID, item, and price, and is formatted thusly:
1,shirt,5
1,pants,3
2,hat,3
I'm trying to find a way to take a user input, say 'shirt' and return the ID of the shop, and the price. How do I do this?
Here is the full code.
namespace Shop
{
public class ShopPick
{
private class Shop
{
public int ShopId { get; set; }
public Dictionary<string, decimal> Goods { get; set; }
}
private readonly List<Shop> _Shops = new List<Shop>();
public void ReadShopData(string filePath)
{
try
{
var records = File.ReadLines(filePath);
foreach (var record in records)
{
var data = record.Split(',');
var ShopId = int.Parse(data[0].Trim());
var Shop = _Shops.Find(r => r.ShopId == ShopId);
if (Shop == null)
{
Shop = new Shop { Goods = new Dictionary<string, decimal>() };
_Shops.Add(Shop);
}
Shop.ShopId = ShopId;
Shop.Goods.Add(data.Skip(2).Select(s => s.Trim()).Aggregate((a, b) => a.Trim() + "," + b.Trim()), decimal.Parse(data[1].Trim()));
}
}
catch (FileNotFoundException ex)
{
Console.WriteLine(ex.Message);
}
}
static void Main(string[] args)
{
var ShopPicker = new ShopPick();
ShopPicker.ReadShopData(
Path.GetFullPath(
Path.Combine(
AppDomain.CurrentDomain.BaseDirectory, #"../../../../Shop_data.csv")
)
);
// Item is found in Shop 2 at price 6.50
var bestShop = ShopPicker.PickBestShop("gac");
Console.WriteLine(bestShop.Item1 + ", " + bestShop.Item2);
Console.WriteLine("Done!");
Console.ReadLine();
}
public Tuple<int, decimal> PickBestShop(string items)
{
string input = Console.ReadLine();
string[] choices = input.Split(',');
foreach(var Shop in _Shops)
{
}
return new Tuple<int, decimal>(0, 0);
}
}
}
The function PickBestShop is where I am stuck
You can use Linq statements. The following code will give you an IEnumerable with the single product Id. Of course you'll need to check for empty lists and nulls and things like that. The code is assuming a product has at least the fields Id and Name.
products.Where(product => product.Name == name).Select(product => product.Id)
I made some edits based on what I could understand from your question. The content in c:\temp\shop.csv looks like:
1,shirt,5
1,pants,3
2,hat,3
3,shirt,6
3,hat,2
4,pants,2
3,trousers,20
5,shirt,5
5,hat,2
And this is edited code:
static void Main(string[] args)
{
//string fileName = Path.GetFullPath(Path.Combine(
// AppDomain.CurrentDomain.BaseDirectory, #"../../../../Shop_data.csv")
// );
string fileName = #"c:\temp\shops.csv";
var ShopPicker = new ShopPick(fileName);
var sample = ShopPicker.PickBestShop("shirt, Hat");
foreach (var shop in sample)
{
Console.WriteLine($"ShopId:{shop.ShopId}, Product: {shop.Product}, Price: {shop.Price}");
}
}
public class ShopPick
{
private List<Shop> _Shops;
public class Shop
{
public int ShopId { get; set; }
public string Product { get; set; }
public decimal? Price { get; set; }
}
public ShopPick(string filePath)
{
var records = File.ReadLines(filePath)
.Select(line => line.Split(','))
.Select(line => new Shop
{
ShopId = int.TryParse(line[0], out int sId) ? sId : -1,
Product = line[1].Trim(),
Price = decimal.TryParse(line[2], out decimal p) ? p : (decimal?)null
});
this._Shops = records.ToList();
}
//public List<Shop> Shops { get { return this._Shops; } }
public IEnumerable<Shop> PickBestShop(string items)
{
List<Shop> shops = new List<Shop>();
//string input = Console.ReadLine();
var choices = items.Split(',').Select(p => p.Trim().ToLower());
foreach (var item in choices)
{
var _shops = this._Shops.Where(s => s.Product.ToLower() == item);
if (_shops.Any())
{
var minPrice = _shops.Min(s => s.Price);
shops.AddRange(_shops.Where(s => s.Price == minPrice));
}
}
return shops;
}
}
Outputs:
ShopId:1, Product: shirt, Price: 5
ShopId:5, Product: shirt, Price: 5
ShopId:3, Product: hat, Price: 2
ShopId:5, Product: hat, Price: 2
Please inform if that wasn't what you meant and\or you require explanation on any part.

C# Assigning to strings from a public class and list

so far my code does the following.
Ask user for a numeric amount for 'players'
Then asks for names for each of the players which is added to a list and class
I'd like to call those names from the list or class (not really sure how class works) and assign it to a new string. Here's what I got so far:
public class NameVariable
{
public int ID { get; set; }
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
bool IsUserWrong = false;
Console.WriteLine("Write amount of players");
while (!IsUserWrong)
{
int TotalPlayers;
while (!Int32.TryParse(Console.ReadLine(), out TotalPlayers))
{
Console.WriteLine("Value must be numeric.");
}
if (TotalPlayers >= 12 && TotalPlayers <= 16)
{
List<NameVariable> PlayerList = new List<NameVariable>();
for (int index = 0; index < TotalPlayers; index++)
{
Console.WriteLine("Enter player {0}'s name:", index + 1);
PlayerList.Add(new NameVariable
{
Name = Console.ReadLine(),
ID = index
});
}
// string player1 = ???
// string player2 = ???
// and so on for 12-16 players
}
else
{
Console.WriteLine("Please enter a value between 12 and 16.");
}
}
}
}
I know that a foreach loop can be used to display all of the variables in the NameVariable class. Would just like to know how to assign each variable to a different string.
Before using the class I just used the list which worked by using
string player1 = PlayerList[0];
string player2 = PlayerList[1];
// and so on for the remaining players
Thanks in advance!
it's just
string player1 = PlayerList[0].Name;
string player2 = PlayerList[1].Name;
...
Essentially your list contains NameVariable objects. PlayerList[index] gives you the object, and .Name gives you the property value of the object.
If you want a specific player name by a specific ID number, you can use LINQ (just to give you a hint)
string player = PlayerList.Where(p => p.ID == WhateverIDNumber).First().Name;
While the answer to your immediate question, i.e., how to access properties of a class object, is as others have shown, I feel like this code has a bigger problem. That is you're trying to do too much in one function, namely, Main(). So I advice to in fact try and refactor your code so that one function does one thing. Something like:
public static int GetNumberOfPlayers()
{
Console.Write("Enter number of players: ");
int totalPlayers;
while (!Int32.TryParse(Console.ReadLine(), out totalPlayers))
{
Console.WriteLine("Value must be numeric.");
}
return totalPlayers;
}
public static List<NameVariable> GetPlayerList(int num)
{
var list = new List<NameVariable>();
for (int i = 0; i < num; i++)
{
Console.WriteLine("Enter player {0}'s name:", i + 1);
list.Add(new NameVariable
{
Name = Console.ReadLine(),
ID = i
});
}
return list;
}
public static void DisplayPlayers(List<NameVariable> list)
{
foreach(var player in list)
{
Console.WriteLine("Player {0}, Name: {1}", player.ID, player.Name);
}
}
public static void CantThinkOfAGoodName()
{
while (true)
{
int totalPlayers = GetNumberOfPlayers();
if (totalPlayers > 16 || totalPlayers < 12)
{
Console.WriteLine("Please enter a value between 12 and 16.");
}
else
{
var playerList = GetPlayerList(totalPlayers);
DisplayPlayers(playerList);
break;
}
}
}
public static void Main()
{
CantThinkOfAGoodName();
Console.ReadLine();
}
Not sure if it helps but you can use an indexer to get players by name.
public NameVariable this[string name]
Let's say you create a class for the colection
public class NameColection : List<NameVariable>
{
public NameVariable this[string name]
{
get
{
return this.FirstOrDefault(n => n.Name == name);
}
}
}
Then you access players by name
var players = new NameColection()
{
new NameVariable() { ID = 1 , Name = "John" },
new NameVariable() { ID = 2 , Name = "Paul" },
new NameVariable() { ID = 3 , Name = "George" },
new NameVariable() { ID = 4 , Name = "Ringo" }
};
var player1 = players["John"];
As NameColection inhertits from List, you will be able to add, remove or modify items the usual way.

Trying to figure out how to access list in a different method

This is my Code inside my Class. I'm trying to figure out how to access Questions list in DisplayQuestion. I have a program.cs that display a menu for a quiz and I can't have anything static.
public string Question { get; set; }
public List<string> Choices { get; set; }
public char[] CorrectChoice = { 'A', 'B', 'C', 'D' };
public List<string> Questions { get; set; }
These are my methods inside my class. I will need to access this list multiple times inside this class.
public void NewQuestion()
{
Questions = new List<string>();
Choices = new List<string>();
Console.WriteLine("Enter the question: ");
Questions.Add(Console.ReadLine());
Console.WriteLine("Enter Choice 1 for the question:");
Choices.Add(Console.ReadLine());
Console.WriteLine("Enter Choice 2 for the question: ");
Choices.Add(Console.ReadLine());
Console.WriteLine("Enter Choice 3 for the question: ");
Choices.Add(Console.ReadLine());
Console.WriteLine("Enter Choice 4 for the question:");
Choices.Add(Console.ReadLine());
// Console.WriteLine("Enter the correct choice(A,B,C,D)");
foreach (string choice in Choices)
{
Console.WriteLine();
Console.WriteLine(choice);
}
}
public void DisplayQuestions()
{
foreach(string question in Questions)
{
Console.WriteLine();
Console.WriteLine(question);
}
}
try declaring and initializing it to null in the global section or create a class with proper getter setter methods for it.
Don't feel constrained to do everything in one class. Even a rough, verbose attempt at separating concerns into separate classes helps with readability, maintainability, and sanity. Then, you're just a thoughtful refactor away from good code.
You are using C#, an OBJECT-oriented language. So go with the grain and embrace using objects.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Quiz_StackOverflow
{
class Program
{
static void Main(string[] args)
{
var quizGenerator = new QuizGenerator();
var quiz = quizGenerator.GenerateQuiz();
var quizProctor = new QuizProctor();
var grade = quizProctor.ProctorQuiz(quiz);
Console.WriteLine(grade.ToString());
Console.WriteLine("Done. Press any key to exit.");
Console.ReadKey();
}
}
public class QuizGenerator
{
public Quiz GenerateQuiz()
{
var problems = GenerateProblems();
var quiz = new Quiz()
{
Problems = problems
};
return quiz;
}
private List<Problem> GenerateProblems()
{
List<Problem> problems = new List<Problem>();
int numChoices = InputValidator.GetPositiveNumber("Enter number of problems: ");
for (int i = 0; i < numChoices; i++)
{
Problem problem = GenerateProblem();
problems.Add(problem);
}
return problems;
}
private Problem GenerateProblem()
{
var question = GenerateQuestion();
var choices = GenerateChoices();
var answer = GenerateAnswer(choices);
var problem = new Problem()
{
Question = question,
Choices = choices,
Answer = answer
};
return problem;
}
private string GenerateQuestion()
{
Console.WriteLine("Enter the question: ");
string question = Console.ReadLine();
return question;
}
private List<string> GenerateChoices()
{
List<string> choices = new List<string>();
int numChoices = InputValidator.GetPositiveNumber("Enter number of choices for the question: ");
for (int i=1; i<=numChoices; i++)
{
string choice = GenerateChoice(i);
choices.Add(choice);
}
return choices;
}
private string GenerateChoice(int index)
{
Console.WriteLine($"Enter Choice {index} for the question: ");
string choice = Console.ReadLine();
return choice;
}
private Answer GenerateAnswer(List<string> choices)
{
Console.WriteLine("Enter the answer: ");
string userChoice = InputValidator.GetUserChoice(new Problem() { Choices=choices });
var answer = new Answer()
{
Value = userChoice
};
return answer;
}
}
public class QuizProctor
{
public Grade ProctorQuiz(Quiz quiz)
{
var answers = new List<Answer>();
foreach(Problem problem in quiz.Problems)
{
Answer answer = ProctorProblem(problem);
answers.Add(answer);
}
Grade grade = quiz.Grade(answers);
return grade;
}
private Answer ProctorProblem(Problem problem)
{
string userChoice = InputValidator.GetUserChoice(problem);
var answer = new Answer()
{
Value = userChoice
};
return answer;
}
}
public class Quiz
{
public List<Problem> Problems { get; set; }
public Grade Grade(List<Answer> answers)
{
List<Answer> answerKey = Problems.Select(x => x.Answer).ToList();
var rawResults = new List<Tuple<Answer, Answer>>();
for(int i=0; i<answers.Count; i++)
{
Answer correct = answerKey[i];
Answer provided = answers[i];
rawResults.Add(new Tuple<Answer, Answer>(correct, provided));
}
return new Grade(rawResults);
}
}
public class Grade
{
private List<Tuple<Answer, Answer>> RawResults { get; set; }
public decimal Percent
{
get { return decimal.Divide(RawResults.Count(x => x.Item1.Equals(x.Item2)), RawResults.Count); }
}
public Grade(List<Tuple<Answer, Answer>> rawResults)
{
RawResults = rawResults;
}
public override string ToString()
{
return string.Format("You scored a {0:P2}.", Percent);
}
}
public class Problem
{
public string Question { get; set; }
public List<string> Choices { get; set; }
public Answer Answer { get; set; }
public string Prompt()
{
Func<int, char> numberToLetter = (int n) =>
{
return (char)('A' - 1 + n);
};
string prompt = Question;
for (int i=0; i<Choices.Count; i++)
{
string choice = Choices[i];
prompt += $"\n{numberToLetter(i+1)}) {choice}";
}
return prompt;
}
}
public class Answer
{
public string Value { get; set; }
public override string ToString()
{
return Value + "";
}
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
return (obj as Answer).Value.Equals(Value);
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
}
public static class InputValidator
{
public static int GetPositiveNumber(string prompt)
{
int number = -1;
while (number < 0)
{
Console.Write(prompt);
string input = Console.ReadLine();
try
{
number = int.Parse(input);
}
catch (Exception)
{
Console.WriteLine("ERROR: Please input a positive number.");
}
}
return number;
}
public static string GetUserChoice(Problem problem)
{
Func<char, int> letterToNumber = (char c) =>
{
if (char.IsLower(c))
{
return (int)(c - 'a' + 1);
}
return (int)(c - 'A' + 1);
};
char userChoiceLetter = '_';
while (!char.IsLetter(userChoiceLetter))
{
Console.WriteLine(problem.Prompt());
Console.Write("Answer: ");
var input = Console.ReadLine();
try
{
userChoiceLetter = char.Parse(input);
}
catch (Exception)
{
Console.WriteLine("ERROR: Please input a letter corresponding to your choice.");
}
}
int answerIndex = letterToNumber(userChoiceLetter) - 1;
return problem.Choices[answerIndex];
}
}
}

I can't Read from FileText C#

I have to make a connection between Students,classes, and year like this: One year can have 1 or more classes and 1 class can have 1 or more students.
I made this with a generic list. The problem is that I have to get the information from one .txt file and I don't know how to do it.
My file is like this:
(Year,Class,Name,Surname,Average).
1 314 George Andrew 8
2 324 Popescu Andrei 9
2 323 Andreescu Bogdan 10
3 332 Marin Darius 9
3 332 Constantin Roxana 10
Code:
public class Student
{
public string Name { get; set; }
public string Surname { get; set; }
public int Average { get; set; }
}
}
public class Grupa
{
public int Name { get; set; }
public List<Student> SetStudent { get; set; }
public Grupa()
{
SetStudent = new List<Student>();
}
public void Print()
{
//Console.WriteLine("Grupa: " + this.Name);
Console.WriteLine("Studentii din grupa: ");
foreach (Student s in this.SetStudent)
{
Console.WriteLine(" " + s.Name+ " " + s.Surname + " --- " + s.Average+"\n");
}
}
}
public class An
{
public int Anul { get; set; }
public List<Grupa> SetGrupa { get; set; }
public An()
{
SetGrupa = new List<Grupa>();
}
public void Print()
{
Console.WriteLine("Anul: " + this.Anul);
Console.WriteLine("Grupele din acest an: ");
foreach (Grupa g in this.SetGrupa)
{
Console.WriteLine(" " + g.Name);
}
}
}
string[] lines = System.IO.File.ReadAllLines(#"D:\C#\Tema1\Tema1.txt");
System.Console.WriteLine("Content Tema1.txt= \n");
foreach (string line in lines)
{
Console.WriteLine("\t" + line);
}
Console.WriteLine("\n Close");
System.Console.ReadKey();
}
You can also use the .NET TextFieldParser for that type of flat file:
var studentList = new List<Student>();
var parser = new Microsoft.VisualBasic.FileIO.TextFieldParser("<file path>");
parser.SetFieldWidths(4, 4, 12, 8, 2);
while (!parser.EndOfData)
{
string[] line = parser.ReadFields();
var student = new Student();
student.Year = int.Parse(line[0]);
student.Class = int.Parse(line[1]);
student.Name = line[2].Trim();
student.Surname = line[3].Trim();
student.Average = int.Parse(line[4]);
studentList.Add(student);
}
You just have to setup the field lengths in the SetFieldWidths function.
Your question is a vague one, are you looking for Linq like that:
// Parsing into objects
var data = System.IO.File
.ReadLines(#"D:\C#\Tema1\Tema1.txt")
.Skip(1) //TODO: comment down this line if your file doesn't have a caption
.Select(line => line.Split('\t'))
.Select(items => new { // or "new Student() {" if you've designed a Student class
Year = int.Parse(items[0]),
Class = int.Parse(items[1]),
Name = items[2],
Surname = items[3],
Average = int.Parse(items[4]), //TODO: Is it Int32 or Double?
});
...
// combining back:
String result = String.Join(Environment.NewLine, data
.Select(item => String.Join("\t",
item.Year, item.Class, item.Name, item.Surname, item.Average));
Console.Write(result);
If you want to have total control over what you want to do, I advise to create a class for each individual studet.
A rough approach:
namespace ConsoleApplication1
{
class Student
{
//Members of class
public int Year;
public int Class;
public string FirstName;
public string LastName;
public int Average;
/// <summary>
/// Gets a line and creates a student object
/// </summary>
/// <param name="line">The line to be parsed</param>
public Student(string line)
{
//being parsing
//split by space
List<String> unfiltered = new List<string>(line.Split(' '));
//a list to save filtered data
List<string> filtred = new List<string>();
//filter out empty spaces...
//There exist much smarter ways...but this does the job
foreach (string entry in unfiltered)
{
if (!String.IsNullOrWhiteSpace(entry))
filtred.Add(entry);
}
//Set variables
Year = Convert.ToInt32(filtred[0]);
Class = Convert.ToInt32(filtred[1]);
FirstName = filtred[2];
LastName = filtred[3];
Average = Convert.ToInt32(filtred[4]);
}
}
class Program
{
static void Main(string[] args)
{
var data = System.IO.File.ReadAllLines(#"d:\data.txt");
//a list to hold students
List<Student> students = new List<Student>();
foreach (var line in data)
{
//create a new student and add it to list
students.Add(new Student(line));
}
//to test, write all names
foreach (var student in students)
{
Console.WriteLine(student.FirstName + " " + student.LastName + Environment.NewLine);
}
//you can calculate average of all students averages!
int sum = 0;
for (int i = 0; i < students.Count; i++)
{
sum += students[i].Average;
}
//print average of all students
Console.WriteLine("Average mark of all students: " + (sum / students.Count));
Console.ReadKey();
}
}
}

How to populate list<t> elements inside a class?

I have a problem about populating list<> elements. I tried to set a value to first element of list<> object but it didn't work. Here is my two classes:
CLASS
class hotel
{
public List<room> rooms = new List<room>();
}
class room
{
public string roomName;
}
Form1.cs
private void Form1_Load(object sender, EventArgs e)
{
string word = "example";
hotel[] h = new hotel[3];
for (int i = 0; i < h.Length; i++)
{
h[i] = new hotel();
h[i].rooms[i].roomName = word;//It gives "Index out of range exception" error.
}
}
You're getting an error because, while you have created a new hotel, you haven't added any rooms to it. Your code would have to do something like the following:
for (int i = 0; i < h.Length; i++)
{
h[i] = new hotel();
h[i].rooms.Add(new room { roomName = word });
}
If you want to add multiple rooms, you would either need to call Add multiple times or do so inside of an inner loop:
for (int i = 0; i < h.Length; i++)
{
h[i] = new hotel();
// Add 10 rooms
for (int a = 0; a < 10; a++)
{
h[i].rooms.Add(new room { roomName = word });
}
}
You have not added a room to the hotel:
h[i] = new hotel();
var room = new room();
room.roomName = word;
h[i].rooms.Add(room);
It may be easier to have a shortcut method in your class:
public class Hotel
{
public Hotel()
{
Rooms = new List<Room>();
}
public List<Room> Rooms { get; private set; }
public string Name { get; private set; }
public Hotel WithName(string name)
{
Name = name;
return this;
}
public Hotel AddRoom(string name)
{
Rooms.Add(new Room { Name = name });
return this;
}
}
public class Room
{
public string Name { get; set; }
}
Returning the Hotel object itself will allow method chaining on the same object to make the operations read fluently.
Demo:
var hotels = new List<Hotel>();
var hiltonHotel = new Hotel()
.WithName("Hilton")
.AddRoom("104")
.AddRoom("105");
hotels.Add(hiltonHotel);
Demo 2:
var hotelNames = new List<string> { "Hilton", "Sheraton", "Atlanta" };
var hotels = new List<Hotel>();
foreach(var hotelName in hotelNames)
{
var hotel = new Hotel()
.WithName(hotelName);
hotels.Add(hotel);
}
Demo 2 with LINQ:
var hotelNames = new List<string> { "Hilton", "Sheraton", "Atlanta" };
var hotels = hotelNames.Select(h => new Hotel().WithName(h)).ToList();
Use, You need to add room to hotel
h[i].rooms.Add(new room {roomName = word});
Instead of
h[i].rooms[i].roomName = word;

Categories