Populate Dictionary - c#

I need to make a "movie ranking" for school.
The language is C#
I want to use a dictionary, where
Key = Movie Name
Value = Assigned stars.
Put it inside a loop and ask for 5 inputs. The code looks something like this:
// Create a dictionary with string key and Int16 value pair
Dictionary<string, Int16> Ranking = new Dictionary<string, Int16>();
for (int i = 1; i < 6; I++)
{
string MovieName = txbPelicula.Text;
Int16 Stars = Convert.ToInt16(txbPuntuacion.Text);
Ranking.Add(MovieName, Stars);
MessageBox.Show("la lista de películas es " + Ranking);
}
Once I exit the loop, sort the Dictionary and Print it ordered by the amount of stars.
Am I well headed?
Some of my classmates used a List, but I don´t understand how will they join Movie Name with it´s Stars.
Thanks

I would use a list of Movie classes or structures. The Movie class needs to contain the name of the movie, and its rating.
class Movie
{
public string Name { get; }
public int Rating { get; set; }
public Movie(string name, int rating)
{
Name = name;
Rating = rating;
}
}
Movie movie = new Movie("Bad movie", 1);
var name = movie.Name;
var rating = movie.Rating;
var movies = new List<Movie>();
//...
foreach (Movie movie in movies.OrderBy(movie => movie.Rating))
{
Console.WriteLine("{0}: {1}", movie.Name, movie.Rating);
}

Related

Place multiple lists next to each other in columns in console

I would like to know how shall I be able to place multiple lists in columns with spacing and without spacing that makes them look like a border-less table
var visitorsName = new List<string>();
var visitorsAge = new List<int>();
var visitorsMark = new List<int>();
for (var number = 1; number <= noOfVisitors; number++)
{
Console.Write("Hi, please type the student's name: ");
var studentName = Console.ReadLine();
visitorsName.Add(studentName);
Console.Write("Please type the student's age: ");
var studentAge = Convert.ToInt32(Console.ReadLine());
visitorsAge.Add(studentAge);
Console.Write("Please type his/her mark: ");
var studentMark = Convert.ToInt32(Console.ReadLine());
visitorsMark.Add(studentMark);
}
Please excuse my inconsistency in naming variables
I would make a Student class with the desired properties instead of using a different list for each one:
class Student
{
public string Name { get; }
public int Age { get; }
public int Mark { get; }
public Student(string name, int age, int mark)
{
Name = name;
Age = age;
Mark = mark;
}
}
Now you can have just a single list of Students:
List<Student> students = new List<Student>
{
new Student("Student 1", 15, 73),
new Student("Student 2", 14, 85)
};
You'll want to create them from console input, but for brevity's sake, I've just initialized the list with some dummy data.
Then it's just a simple matter of iterating through the list and writing your pseudo-columned values:
foreach (Student student in students)
{
Console.WriteLine("{0,-20}{1,-5}{2,-3}", student.Name, student.Age, student.Mark);
}
And that should give you something that looks like this:
Student 1 15 73
Student 2 14 85

List Collection Class

Hello let me describe i don't have any errors in my code , i am just asking a very basic question here RELATED TO list collection class let see i have a class called customer
class customer
{
public int Id { get; set; }
public string Name { get; set; }
public int Salary { get; set; }
}
in my main method i created an array of customer and initialize those properties that is present in my customer class
static void Main(string[] args)
{
customer[] customers = new customer[3];
customers[0] = new customer
{
Id = 1,
Name = "A",
Salary = 30000
};
customers[1]=new customer
{
Id = 2,
Name = " B",
Salary = 50000
};
customers[2] = new customer
{
Id = 3,
Name = "C",
Salary = 90000
};
List<customer> Cust= new List<customer>(2);
Cust.Add(customers[0]);
Cust.Add(customers[1]);
Cust.Add(customers[2]);
for (int i = 0; i < Cust.Count; i++)
{
customer C = Cust[i];
Console.WriteLine("Id = {0} & Name = {1} & Salary = {2}",C.Id,C.Name,C.Salary);
}
Console.ReadLine();
}
Okay! so this code is working so perfectly nice , but my question is that at last we created a list called cust and add all the custemers in to it , so why is it necessary to make another object with type customer as i did in for loop
customer C = Cust[i];
why can i don't call my code like this
console.WriteLine{Cust[i]}
As far as i know when we create object of the class than we can easily acces the code inside that class with that instance variable . so why not here?
In your for loop, you're not creating a new customer, you're just creating a reference to the existing one:
for (int i = 0; i < Cust.Count; i++)
{
customer C = Cust[i]; //<- not new, just a reference to the customer at index
Console.WriteLine("Id = {0} & Name = {1} & Salary = {2}",C.Id,C.Name,C.Salary);
}
A more concise way to loop is to use foreach instead of for (NOTE: using C# 6.0 string interpolation):
foreach(var c in Cust)
Console.WriteLine($"Id = {c.Id} & Name = {c.Name} & Salary = {c.Salary}");
To do what you were asking to do, you would first need to override the ToString() method on your class. The ToString() method will be called implicitly by Console.WriteLine:
class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public int Salary { get; set; }
public override string ToString()
{
return string.Format("Id = {0} & Name = {1} & Salary = {2}", Id, Name, Salary);
}
}
Now that you have a default way to represent a customer as a string, you can do exactly what you were asking to do:
for (int i = 0; i < Cust.Count; i++)
{
Console.WriteLine(Cust[i]);
}
And, now that you have this, you can do it in an even easier way. The following will implicitly pass each item to Console.WriteLine(), which will call the item's ToString() method:
customers.ForEach(Console.WriteLine);
If for some reason you DON'T want to override the ToString method, you can still access the instance properties using the index without creating a new object, like so:
for (int i = 0; i < Cust.Count; i++)
{
Console.WriteLine("Id = {0} & Name = {1} & Salary = {2}",
Cust[i].Id, Cust[i].Name, Cust[i].Salary);
}

Add values to Dictionary<int,class> not all at once

I'm trying to store data in a dictionary where the key is an ID and the values are of a class type. The class properties are not all added at the same time so I haven't used a constructor - unless there is a way to add new values using a constructor at a different times? The code below compiles, but I get a run time error saying the key has already been added.Thanks for the help.
public class Students
{
public string FirstName { get; set; }
public string SurName { get; set; }
public int Age { get; set; }
public double Score { get; set; }
}
public void cmdTEST_Click(object sender, EventArgs e)
{
Dictionary<int, Students> Data = new Dictionary<int, Students>();
Data.Add(5, new Students { FirstName = "Bob" });
Data.Add(5, new Students { Age = 34 }); // run time error - "key already added"
Data.Add(5, new Students { Score = 62 });
// extract data
double Score5 = Data[5].Score;
double Age5 = Data[5].Age;
}
You are adding same key multiple times which is not allowed. You can add all properties at once like below
Dictionary<int, Students> Data = new Dictionary<int, Students>();
Data.Add(5, new Students { FirstName = "Bob", Age = 34, Score = 62 });
And if you want to add values later you can use key to add values
Data.Add(5, new Students { FirstName = "Bob"});
Data[5].Age = 34;
Data[5].Score = 62;

Sort text file data into an array

I'm working on a homework problem for my computer science class. A cities census data is on a text file holding records for its citizens. Each line will have four fields(age, gender, marital status, and district) of different data types separated by a comma. For example, 22, F, M, 1.
How should I approach this? My thoughts are that I should use two 1D arrays, one for age and one for district. I need to be able to later count how many people are in each district, and how many people are in different age groups for the whole city.
How do I read each line and get the info I want into each array?
edit**
This is what I've managed to do so far. I'm trying to separate my data from fields into four different arrays. This is where I'm stuck.
FileStream fStream = new FileStream("test.txt", FileMode.Open, FileAccess.Read);
StreamReader inFile = new StreamReader(fStream);
string inputRecord = "";
string[] fields;
int[] ageData = new int[1000];
string[] genderData = new string[1000];
string[] maritalData = new string[1000];
int[] districtData = new int[1000];
inputRecord = inFile.ReadLine();
while (inputRecord != null)
{
fields = inputRecord.Split(',');
int i = 0;
ageData[i] = int.Parse(fields[0]);
genderData[i] = fields[1];
maritalData[i] = fields[2];
districtData[i] = int.Parse(fields[3]);
i++;
inputRecord = inFile.ReadLine();
}
edit 2**
First question, I've decided to use the below code to find out how many citizens are in each district of the census data.
for (int x = 1; x <= 22; x++)
for (int y = 0; y < districtData.Length; y++)
if (districtData[y] == x)
countDist[x]++;
for (int x = 1; x <= 22; x++)
Console.WriteLine("District " + x + " has " + countDist[x] + " citizens");
In my .Writeline when x reaches two digits it throws off my columns. How could I line up my columns better?
Second question, I am not quite sure how to go about separating the values I have in ageData into age groups using an if statement.
It sounds like each of the four fields have something in common... they represent a person surveyed by the census. That's a good time to use a class along the lines of
public class Person
{
public int Age { get; set; }
public string Gender { get; set; }
public string MaritalStatus { get; set; }
public int District { get; set; }
}
Then, just read in all of the lines from the text file (if it's small, it's fine to use File.ReadAllLines()), and then create an instance of Person for each line in the file.
You can create a
List<Person> people;
to hold the Person instances that you parse from the text file.
Since the lines appear to be separated by commas, have a look at String.Split().
UPDATE
The attempt in your edit is pretty close. You keep creating a new i and initializing it to 0. Instead, initialize it outside your loop:
int i = 0;
while (inputRecord != null)
{
fields = inputRecord.Split(',');
Also you may want to trim excess spaces of of your input. If the fields are separated with ", " rather than just "," you will have excess spaces in your fields.
genderData[i] = fields[1].Trim();
maritalData[i] = fields[2].Trim();
How about this?
List<string[]> o = File.ReadAllLines(#"C:\TestCases\test.txt").Select(x => x.Split(',')).OrderBy(y => y[0]).ToList();
Each person is a string array in the list.
Each property is a index in the array eg: age is first.
The above code reads all lines comma delimits them orders them by age and adds them to the list.
public static class PersonsManager
{
public static PersonStatistics LoadFromFile(string filePath)
{
var statistics = new PersonStatistics();
using (var reader = new StreamReader(filePath))
{
var separators = new[] { ',' };
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if (string.IsNullOrWhiteSpace(line))
continue; //--malformed line
var lParts = line.Split(separators, StringSplitOptions.RemoveEmptyEntries);
if (lParts.Length != 4)
continue; //--malformed line
var person = new Person
{
Age = int.Parse(lParts[0].Trim()),
Gender = lParts[1].Trim(),
MaritalStatus = lParts[2].Trim(),
District = int.Parse(lParts[3].Trim())
};
statistics.Persons.Add(person);
}
}
return statistics;
}
}
public class PersonStatistics
{
public List<Person> Persons { get; private set; }
public PersonStatistics()
{
Persons = new List<Person>();
}
public IEnumerable<Person> GetAllByGender(string gender)
{
return GetByPredicate(p => string.Equals(p.Gender, gender, StringComparison.InvariantCultureIgnoreCase));
}
//--NOTE: add defined queries as many as you need
public IEnumerable<Person> GetByPredicate(Predicate<Person> predicate)
{
return Persons.Where(p => predicate(p)).ToArray();
}
}
public class Person
{
public int Age { get; set; }
public string Gender { get; set; }
public string MaritalStatus { get; set; }
public int District { get; set; }
}
Usage:
var statistics = PersonsManager.LoadFromFile(#"d:\persons.txt");
var females = statistics.GetAllByGender("F");
foreach (var p in females)
{
Console.WriteLine("{0} {1} {2} {3}", p.Age, p.Gender, p.MaritalStatus, p.District);
}
I hope it helps.

using linq to merge items together in a collection

I have a list of objects (call them type salesItems) Lets say these items have 50 properties, with Name, price, quantity being 3 of them). I would like to know how to merge the list together combining any salesItems by name using the following logic:
If there are multiple salesOrders that have the same Name:
Combine them into one SalesOrder with the same Name
Set the quantity to the sum of the quantities
Set the price, and all of the other properties using the values of the first
I would like to do with linq. I realize i could use a big for each c# loop instead.
If there are additional items in the list I would like to follow similar logic for those as well.
EX: A salesOrder list with (A,B,C,D,E)
A: Name=ball Price= 2.24 Quantity=1 (other values = bla bla)
B: Name= ball Price = 15.33 Quantity=3 (other values)
c: Name= bat Price = 22.14 Quantity=3 (other values)
D: Name= bat Price= 19.22 Quantity=2 (other values)
E: Name = ball Price=4.32 Quantity=2 (other values)
Result list I want 2 Sales orders in list (A,C) A: Name=ball Price=
2.24 Quantity=6 (other values = bla bla from a's properties) c: Name= bat Price = 22.14 Quantity=5 (other values from c's
properties)
You want linq's .GroupBy method!!!
I've defined your class as:
public class SalesOrder
{
public string Name { get; set; }
public double Price { get; set; }
public int Quantity { get; set; }
public SalesOrder(string Name, double Price, int Quantity)
{
this.Name = Name;
this.Price = Price;
this.Quantity = Quantity;
}
}
then I have created a list of your orders like this:
List<SalesOrder> Orders = new List<SalesOrder>()
{
new SalesOrder("Ball", 2.24, 1),
new SalesOrder("Ball", 15.33, 3),
new SalesOrder("Bat", 22.14, 3),
new SalesOrder("Bat", 19.22, 2),
new SalesOrder("Ball", 4.32, 2)
};
and grouped them by the name before selecting the values you want for each group into a new instance of the SalesOrder class like this:
List<SalesOrder> Combined_Orders = Orders
.GroupBy (o => o.Name)
.Select (o => new SalesOrder(o.Key, o.Select (x => x.Price).First(), o.Sum(x => x.Quantity)))
.ToList();
UPDATE: In response to OP's comment
As the real SalesOrder will have hundreds of properties, you can avoid typing them all out in the linq query by adding a constructor to the SalesOrder class that accepts the result of the group by as an argument, then do all the work in the constructor. While it doesn't stop you from having to type out all the properties, it does mean that its neatly abstracted away. Also this way it forces/enables you to decide on what to do with each of the properties (first/sum/average).
To do this you will need a second constructor that looks like this:
public SalesOrder(IGrouping<string, SalesOrder> Group)
{
this.Name = Group.Key;
this.Price = Group.First().Price;
this.Quantity = Group.Sum(g => g.Quantity);
// do all other properties here too
}
Then update the group by to look like this (note that only the result of the grouping "g" is passed into the constructor now):
List<SalesOrder> Combined_Orders = Orders
.GroupBy (o => o.Name)
.Select (g => new SalesOrder(g))
.ToList();
Hi You can use the following code,
class SalesItem
{
public string Name { get; set; }
public int Price { get; set; }
public int Quantity { get; set; }
}
class SalesOrder
{
public void LoadItems()
{
List<SalesItem> SalesItems = new List<SalesItem>();
SalesItem salesitem = new SalesItem()
{
Name = "Ball",
Price = 12,
Quantity = 1
};
SalesItems.Add(salesitem);
salesitem = new SalesItem()
{
Name = "Ball",
Price = 36,
Quantity = 3
};
SalesItems.Add(salesitem);
salesitem = new SalesItem()
{
Name = "Bat",
Price = 50,
Quantity = 1
};
SalesItems.Add(salesitem);
salesitem = new SalesItem()
{
Name = "Ball",
Price = 84,
Quantity = 7
};
SalesItems.Add(salesitem);
salesitem = new SalesItem()
{
Name = "Bat",
Price = 150,
Quantity = 3
};
SalesItems.Add(salesitem);
GroupOrders(SalesItems);
}
public List<SalesItem> GroupOrders(List<SalesItem> SalesItems)
{
var list = from item in SalesItems
group item by item.Name into orders
select new SalesItem
{
Name = orders.Key,
Price = orders.Sum(X=>X.Price),
Quantity = orders.Sum(X=>X.Quantity)
};
List<SalesItem> resultList = new List<SalesItem>();
foreach (SalesItem saleitem in list)
{
resultList.Add(saleitem);
}
return resultList;
}
}

Categories

Resources