I have a textfile, like this:
Tokyo
Japan
8797987
Amsterdam
Nederland
88788787
Den Haag
Nederland
787875454
Madrid
Spain
7877878
So in the batch there are three items:
Capital
Country
Population
and I am using the command Batch from MoreLinq.
I know to do it with a dictionary.
But how to manage this with three items for every batch?
What I mean with that is that for example you are searching for a capital and country that you will returned the capital + the country + the population
I try it like this:
public interface IDatabase
{
int GetPopulation(string name);
}
public class SingleTOnDatabase : IDatabase
{
private System.Collections.Generic.List capitols;
private SingleTOnDatabase()
{
Console.WriteLine("Initializing database");
capitols = File.ReadAllLines("Capitols.txt")
.Batch(3)
.ToList(
list => list.ElementAt(0).Trim(),
list => list.ElementAt(1).Trim(),
list => int.Parse((list.ElementAt(2)))
);
}
public int GetPopulation(string name)
{
return capitols[name];
}
private static Lazy<SingleTOnDatabase> instance = new Lazy<SingleTOnDatabase>(() => new SingleTOnDatabase());
public static SingleTOnDatabase Instance => instance.Value;
}
public class Program
{
static void Main(string[] args)
{
var db = SingleTOnDatabase.Instance;
var city = "Den Haag";
var Country = "Nederland";
Console.WriteLine($"{Country} with {city} has population of: {db.GetPopulation(city)}");
Console.Read();
}
}
You should never try to use text files as databases (if this is a serious job, for hobby projects who cares).
I revised your "batch" plus GetPopulation (and also added GetCapitol):
public interface IDatabase
{
int? GetPopulation(string name);
Capitol GetCapitol(string name);
}
public class Capitol
{
public string CapitolName { get; set; }
public string Country { get; set; }
public int? Population { get; set; }
}
public class SingleTOnDatabase : IDatabase
{
private System.Collections.Generic.List<Capitol> capitols;
private SingleTOnDatabase()
{
Console.WriteLine("Initializing database");
int pop;
capitols = (from batch in File.ReadAllLines("Capitols.txt").Batch(3)
let bArr = batch.ToArray()
where bArr.Length == 3
select new Capitol
{
CapitolName = bArr[0].Trim(),
Country = bArr[1].Trim(),
Population = int.TryParse(bArr[2], out pop) ? pop : (int?)null
}).ToList();
}
public int? GetPopulation(string name)
{
var capitol = GetCapitol(name);
return capitol?.Population;
}
public Capitol GetCapitol(string name)
{
return capitols.SingleOrDefault(c => c.CapitolName.ToLower().Trim() == name.ToLower().Trim());
}
private static Lazy<SingleTOnDatabase> instance = new Lazy<SingleTOnDatabase>(() => new SingleTOnDatabase());
public static SingleTOnDatabase Instance => instance.Value;
}
public class Program
{
static void Main(string[] args)
{
var db = SingleTOnDatabase.Instance;
var city = "Den Haag";
var Country = "Nederland";
Console.WriteLine($"{Country} with {city} has population of: {db.GetPopulation(city)}");
var city2 = "Tokyo";
var cap = db.GetCapitol(city2);
if (cap == null)
{
Console.WriteLine($"Unknown city [{city2}].");
}
else
{
Console.WriteLine($"{cap.CapitolName} is the capital of {cap.Country} and has population of: {cap.Population}");
}
Console.Read();
}
}
Note: With your given sample text at top, this is the output I get:
Initializing database
Nederland with Den Haag has population of: 787875454
Tokyo is the capital of Japan and has population of: 8797987
Related
is it possible to use with expressions for a record with custom properties?
public record Person
{
public string LastName { get; }
public string FirstName { get; }
public Person(string first, string last) => (FirstName, LastName) = (first, last);
}
static void Main(string[] args)
{
var p = new Person("adam","smith");
// var p2 = p with { first = "joe" }; // error CS0117: 'Person' does not contain a definition for 'first'
// var p3 = p with { FirstName = "joe" }; // error CS0200: Property or indexer 'Person.FirstName' cannot be assigned to -- it is read only
}
https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9#record-types
You need to use the init accessor, check the below example:
class Program
{
static void Main(string[] args)
{
var c1 = new Candidate("Donald","Trump");
var c2 = new Candidate("Donald", "Trump");
var c3 = c1 with { Surname = "Duck" };
}
}
public record Candidate
{
public string FirstName { get; init; }
public string Surname { get; init; }
public Candidate(string Fname, String Sname) => (Fname, Sname) = (FirstName, Surname);
}
As an aside, if you get the following error after using Init, there is a day 0 bug:
predefined type 'System.Runtime.compilerServices.IsexternalInit is not defined or imported'
If so you need to paste in the following namespace/class into your solution:
namespace System.Runtime.CompilerServices
{
public class IsExternalInit { }
}
As an final aside, you can cut your code down massively by using positional records as shown below, that way you do not need a constructor or any properties:
class Program
{
static void Main(string[] args)
{
var c1 = new Candidate("Donald", "Trump");
Concsole.ReadLine();
}
}
record Candidate(string FirstName, string Surname);
The above example will auto set init, be aware though records created without an access modifier default to public, not private like classes.
The properties need to be declared with init;
public record Person
{
public string LastName { get; init; }
public string FirstName { get; init; }
public Person(string first, string last) => (FirstName, LastName) = (first, last);
}
I am learning C# dictionary and I am confused how to do this
I have a Dictionary of students names. and I would like to assign another dictionary to that.
my input similar to this
Student1:
Math,9
Science,5
English,2
Student2:
Math,9
Science,10
English,7
I tried to create a class called Info and here is my code
public class Info
{
public string course { get; set; }
public int grade { get; set; }
public Info(string c, int g)
{
course = c;
grade = g;
}
internal IDictionary<string, Info> infoDic { get; private set; }
public void Set(string Sname, string course, int grade)
{
Student s = new Student(Sname);
var infor = new Info(course, grade);
infoDic = new Dictionary<string, Info>();
infoDic.Add(s.Name, infor);
//return infoDic;
}
public Dictionary<string, Info> retrieve (string name)
{
Student s = new Student(name);
return infoDic;
}
}
}
and here is another attempt:
I tried to make the class Info , and in the main I create the Dictionary and give the values, but the problem is I have lets say 3 courses and 10 students, and sometimes I need to retrieve only the math grades for all students.
How to improve the code to differentiate between the courses? Or how to make the course name as another key?
public class Info
{
public string course { get; set; }
public int grade { get; set; }
public Info(string c, int g)
{
course = c;
grade = g;
}
}
class Test
{
public static void Main(string[] args)
{
Dictionary<string, Info> information = new Dictionary<string, Info>();
Info i1 = new Info("math", 9);
information.Add("Student1", i1);
Info i2 = new Info("science", 11);
information.Add("Student1", i2);
Info i3 = new Info("math", 13);
information.Add("student2", i3);
foreach (KeyValuePair<string, Info> eee in information)
{
Console.WriteLine("{0}\t{1}\t{2}", eee.Key, eee.Value.type, eee.Value.count);
}
}
}
I need two methods one to set the values that user enters and the other to retrieve a certain course values when the user requires them
Is there Any suggestions?
Split the problem into separate concerns.
Use the Student and Info classes just to store data. Importantly, every Student holds a collection of his courses.
public class Student {
public Student(string name) {
Name = name;
Infos = new List<Info>();
}
public string Name {get; set;}
public ICollection<Info> Infos {get; set;}
}
public class Info {
public Info(string course, int grade) {
Course = course;
Grade = grade;
}
public string Course { get; set; }
public int Grade { get; set; }
}
Data access is handled by a different class StudentRepository.
The central dictionary is of type IDictionary<string, Student> with the Student name as key and hidden inside the repository.
using System.Linq;
public class StudentRepository {
public StudentRepository() {
_studentsByName = new Dictionary<string, Student>();
}
// keep data store private so we can change the implementation
private IDictionary<string, Student> _studentsByName {get; set;}
public void Add(Student student) {
if (_studentsByName.ContainsKey(student.Name)) {
throw new ArgumentException($"Student '{student.Name}' already stored.");
}
_studentsByName.Add(student.Name, student);
}
public Student Get(string studentName) {
if (_studentsByName.ContainsKey(studentName)) {
return _studentsByName[studentName];
}
throw new ArgumentException("No student '" + studentName + "' stored.");
}
// Find Grade for certain student and course
public int GetGrade(string studentName, string course) {
if (_studentsByName.ContainsKey(studentName)) {
var student = _studentsByName[studentName];
var courseInfo = student.Infos.FirstOrDefault(i => i.Course == course);
if (courseInfo != null) {
return courseInfo.Grade;
}
else {
throw new ArgumentException(
$"Student '{studentName}' did not take the course '{course}'.");
}
}
else {
throw new ArgumentException($"No student '{studentName}' found.");
}
}
// Get dictionary of all students that took a certain course. Key: student name
public IDictionary<string, Info> GetCoursesByStudentName(string course) {
// Use LINQ to retrieve the infos you need.
// Here I create a new dictionary with Student name as Key and
// the first matching course info found as value.
// (Students that did not take this course are not in this dictionary):
return _studentsByName
.Where(kvp => kvp.Value.Infos.Any(i => i.Course == course))
.ToDictionary(kvp => kvp.Key,
kvp => kvp.Value.Infos.First(i => i.Course == course));
}
}
Usage example:
const string MathCourseName = "Math";
var Student1 = new Student("Alice");
Student1.Infos.Add(new Info(MathCourseName, 4));
var Student2 = new Student("Bob");
Student2.Infos.Add(new Info(MathCourseName, 2));
var Student3 = new Student("Cesar");
Student3.Infos.Add(new Info("English", 3));
var repository = new StudentRepository();
repository.Add(Student1);
repository.Add(Student2);
repository.Add(Student3);
foreach(var kvp in repository.GetCoursesByStudentName(MathCourseName)) {
Console.WriteLine(kvp.Key + ": " + kvp.Value.Course + " - " + kvp.Value.Grade);
}
var bobsMathGrade = repository.GetGrade("Bob", MathCourseName);
Console.WriteLine("Bobs math grade: " + bobsMathGrade);
C# Fiddle for this example
What i understood from your statement, you need two methods: One for setting user values and other for getting user's course value, i've slightly modified your code in order to fulfill you requirement, you can do like this:
public class Info
{
public string course { get; set; }
public int grade { get; set; }
public Info(string c, int g)
{
course = c;
grade = g;
}
}
public class Student
{
public Dictionary<string,Dictionary<string,int>> student { get; set; }
public Student()
{
student = new Dictionary<string, Dictionary<string, int>>();
}
/// <summary>
///
/// </summary>
public void SetValue(string studentName, Info info)
{
if (!student.ContainsKey(studentName))
{
Dictionary<string, int> stud_info = new Dictionary<string, int>();
stud_info.Add(info.course, info.grade);
student.Add(studentName, stud_info);
}
else
{
student[studentName].Add(info.course, info.grade);
}
}
public Dictionary<string,int> GetValue(string studentName, string course)
{
Dictionary<string, int> info = new Dictionary<string, int>();
if (student.ContainsKey(studentName))
{
if (student[studentName].ContainsKey(course))
{
int grade = 0;
if(student[studentName].TryGetValue(course, out grade))
{
info.Add(course, grade);
return info;
}
}
}
return info;
}
}
public class Program
{
public static void Main(string[] args)
{
Student student = new Student();
Info i1 = new Info("math", 9);
student.SetValue("Student1", i1);
Info i2 = new Info("science", 11);
student.SetValue("Student1",i2);
Info i3 = new Info("math", 13);
student.SetValue("Student2", i3);
Dictionary<string, int> value = student.GetValue("Student2", "math");
//Grade of math for student2
Console.WriteLine("Grade: {0}", value["math"]);
}
}
In the top of the class
public class Country
{
public string country { get; set; }
}
And how i build the links
public void ImagesLinks()
{
try
{
int counter = 0;
int cnt = 0;
foreach (string countryCode in countriescodes)
{
imagesUrls.Add(countriesnames[counter]);
counter++;
cnt++;
for (; cnt < DatesAndTimes.Count(); cnt++)
{
string imageUrlIrTrue = firstUrlPart + countryCode + secondUrlPart + DatesAndTimes[cnt] + thirdUrlPart + "true";
string imageUrlIrFalse = firstUrlPart + countryCode + secondUrlPart + DatesAndTimes[cnt] + thirdUrlPart + "false";
imagesUrls.Add(imageUrlIrTrue);
imagesUrls.Add(imageUrlIrFalse);
if (cnt % 10 == 0)
break;
}
}
}
catch(Exception err)
{
string myerr = err.ToString();
}
}
What i have in the end is a List with names and the links of each name.
For example in the index 0 i have the name: Europe
Then then ext 18 indexs are links of Europe
Then the next name is in index 21: Alps
And then the next 18 indxs of Alps
What i want to do is using the class Country is when i will type for example:
Country. ( After the point i will have properties of all the names Europe ,Alps and so on so i can select one of the names ) Same like if i will type for example File. so after the point i will have properties like Create Copy and so on so when i will type Country i will have all the countries names Europe, Alps....
And then if i will make a loop over one of the names it will loop over it's 18 items. For example:
For (int i = 0; i < Country.Europe; i++)
{
// something to do with Country.Europe[i]
}
Or
For (int i = 0; i < Country.Alps; i++)
{
// something to do with Country.Alps[i]
}
So maybe each name/country should be a List of it self ?
For (int i = 0; i < Country.Europe.Count(); i++)
{
// something to do with Country.Europe[i]
}
But the idea is that i will be able easy to select a name from a properties list and when loop over the name it will loop over it's 18 items.
I threw this together real fast - it is how I would probably handle it. I added a little more, I think you just need a class to handle countries. In any case, you would need to adjust your loop to create this structure, so this isn't a perfect solution - but it's how I would do it. You could also use linq instead of loops, I did this more as a class-based answer than a "pretty" answer.
namespace classTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
World newWorld = new World();
Continent Europe = new Continent();
Europe.name = "Europe";
Country England = new Country();
England.name = "England";
List<string> imageUrl = new List<string>();
imageUrl.Add("url1-England");
imageUrl.Add("url2-England");
imageUrl.Add("url3-England");
England.imageUrls = imageUrl;
Europe.countries.Add(England);
newWorld.continents.Add(Europe);
Country France = new Country();
France.name = "France";
imageUrl = new List<string>();
imageUrl.Add("url1-France");
imageUrl.Add("url2-France");
imageUrl.Add("url3-France");
France.imageUrls = imageUrl;
Europe.countries.Add(France);
foreach (Continent continent in newWorld.continents)
{
Console.WriteLine(continent.name);
foreach (Country country in continent.countries)
{
Console.WriteLine(country.name);
foreach(string imageUri in country.imageUrls)
{
Console.WriteLine(imageUri);
}
}
}
}
}
public class World
{
public List<Continent> continents;
public World()
{
continents = new List<Continent>();
}
}
public class Continent
{
public string name;
public List<Country> countries { get; set; }
public Continent()
{
name = string.Empty;
countries = new List<Country>();
}
}
public class Country
{
public string name { get; set; }
public List<string> imageUrls { get; set; }
public Country()
{
name = string.Empty;
imageUrls = new List<string>();
}
}
}
In the following solution, I use an outer wrapper Country that provides static references to instances for the continents (e.g. Europe). The continents implement IEnumerable, so you can iterate over all countries of this continent or use LINQ to filter them.
public class CountryData : IEquatable<CountryData>{
public string Link { get; set; }
public bool Equals(CountryData other) {
if (other == null) {
return false;
}
return StringComparer.Ordinal.Equals(Link, other.Link);
}
public override int GetHashCode() {
return Link.GetHashCode();
}
}
public static class Country {
public static readonly Europe Europe = new Europe();
}
public class Europe : IEnumerable<CountryData> {
private List<CountryData> All => new List<CountryData> {
Austria,
Belgium
};
public CountryData Austria = new CountryData { Link = #"\Country\Austria" };
public CountryData Belgium = new CountryData { Link = #"\Country\Belgium" };
IEnumerator<CountryData> IEnumerable<CountryData>.GetEnumerator() {
return All.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return All.GetEnumerator();
}
}
Usage examples:
var austria = Country.Europe.Austria;
var belgium = Country.Europe.Single(c => c.Link.Contains("Belgium"));
foreach (var european in Country.Europe) {
Console.WriteLine(european.Link);
}
Edit
If you want to compare countries, CountryData must implement IEquatable<CountryData>
Usage example:
var isSame = Country.Europe.Austria == Country.Europe.Belgium;
// isSame is false
I am trying to implement a reflexive association in C# sharp but couldn't find any example on the web.
I have come up with following
class Employee
{
public string Name { get; set; }
public Employee Boss { get; set; }
public List<Employee> Junoirs;
public Employee (string name)
{
Junoirs = new List<Employee>();
Name = name;
}
static void Main(string[] args)
{
Employee tom = new Employee("Tom");
Employee marry = new Employee("Marry");
Employee jhon = new Employee("Jhon");
Employee foo = new Employee("Foo");
Employee bar = new Employee("Bar");
tom.Junoirs.AddRange(new Employee[] { marry, jhon });
marry.Boss = tom;
jhon.Boss = tom;
marry.Junoirs.AddRange(new Employee[] { foo, bar });
foo.Boss = marry;
bar.Boss = marry;
}
}
Is this a valid example of reflexive association?
How can I automatically add tom as Boss of employees marry and jhon as I add them to list of Junoirs of tom?
You can use methods to add/remove juniors.
If you need add/remove-functionality on the Juniors property, you can implement your own IList or ICollection which handles the book-keeping.
public class Employee
{
public string Name { get; set; }
public Employee Boss
{
get { return _boss; }
set
{
_boss?.RemoveJunior(this);
value?.AddJunior(this);
}
}
public IReadOnlyList<Employee> Juniors => _juniors.AsReadOnly();
private Employee _boss = null;
private readonly List<Employee> _juniors = new List<Employee>();
public Employee(string name)
{
Name = name;
}
public void AddJunior(Employee e)
{
// Remove from existing boss' list of employees
// Can't set Boss property here, that would create infinite loop
e._boss?.RemoveJunior(e);
_juniors.Add(e);
e._boss = this;
}
public void RemoveJunior(Employee e)
{
_juniors.Remove(e);
e._boss = null;
}
}
public class EmployeeTests
{
[Fact]
public void SettingBoss_AddsToEmployee()
{
var b = new Employee("boss");
var e1 = new Employee("1");
e1.Boss = b;
Assert.Same(b, e1.Boss);
Assert.Contains(e1, b.Juniors);
}
[Fact]
public void AddEmployee_SetsBoss()
{
var b = new Employee("boss");
var e1 = new Employee("1");
b.AddJunior(e1);
Assert.Same(b, e1.Boss);
Assert.Contains(e1, b.Juniors);
}
[Fact]
public void NullBoss_RemovesEmployee()
{
var b = new Employee("boss");
var e1 = new Employee("1");
b.AddJunior(e1);
e1.Boss = null;
Assert.Null(e1.Boss);
Assert.DoesNotContain(e1, b.Juniors);
}
[Fact]
public void RemoveEmployee_NullsBoss()
{
var b = new Employee("boss");
var e1 = new Employee("1");
b.AddJunior(e1);
b.RemoveJunior(e1);
Assert.Null(e1.Boss);
Assert.DoesNotContain(e1, b.Juniors);
}
}
It's not impossible that my question has already been answered here, but unfortunately when it comes to LINQ I can't always find the right search terms.
Given the underlying source code how do you think I can reuse Selectors.CustomerDTO selector within Selectors.CustomerExtendedDTO?
It should be possible since the input database entity is the same.
class Program
{
static void Main(string[] args)
{
using (NorthwindEntities ctx = new NorthwindEntities())
{
foreach (var item in ctx.Customers.Where(c => c.CompanyName.StartsWith("A")).Select(Selectors.CustomerDTO))
{
Console.WriteLine("CompanyName: {0}", item.CompanyName);
Console.WriteLine();
}
foreach (var item in ctx.Customers.Where(c => c.CompanyName.StartsWith("A")).Select(Selectors.CustomerExtendedDTO))
{
Console.WriteLine("CompanyName: {0}", item.CompanyName);
Console.WriteLine("ContactName: {0}", item.ContactName);
Console.WriteLine();
}
Console.ReadLine();
}
}
}
class CustomerDTO
{
public string CustomerID { get; set; }
public string CompanyName { get; set; }
}
class CustomerExtendedDTO : CustomerDTO
{
public string ContactName { get; set; }
public string Address { get; set; }
}
static class Selectors
{
internal static Expression<Func<Customers, CustomerDTO>> CustomerDTO
{
get
{
return c => new CustomerDTO
{
CustomerID = c.CustomerID,
CompanyName = c.CompanyName
};
}
}
internal static Expression<Func<Customers, CustomerExtendedDTO>> CustomerExtendedDTO
{
get
{
return c => new CustomerExtendedDTO
{
CustomerID = c.CustomerID,
CompanyName = c.CompanyName,
Address = c.Address,
ContactName = c.ContactName
};
}
}
}
Such thing would be very useful when the inherited projection entity does not only contain two properties but several dozens.
Thanks for any ideas.