Students students=(FileRoutines.LoadStudents(STUDENT_FILE)); - c#

I am taking a C# class and I have a project. The project has code written for void Main(). Here is the first part of the code in Main():
const string STUDENT_FILE = #"C:\TEMP\Students.txt";
const string ASSIGNMENT_FILE = #"C:\Temp\Assignments.txt";
Students students=FileRoutines.LoadStudents(STUDENT_FILE));
I have to write a 3 classes Students, student, and FileRoutines. I cannot seem to figure out what needs to go into the Students class to get the instance to work. I can write the following:
string[] students = FileRoutine.LoadStudents(STUDENT_FILE)
and get the students array I am trying to do with:
Students students=FileRoutines.LoadStudents(STUDENT_FILE));
but I cannot seem to get this instance to work. This is the contents of the file:
122338 Weltzer Teresa
123123 Wang Choo
123131 Adams James
123132 Binkley Joshua Troy
123139 Howard Tyler
123160 King Alma
I have seen this project posted before, but no one seems to be able to answer the question, but instead offer other alternatives.
I know when creating an instance of a class I need to have a constructor or constructors, but I am not doing:
Students students = new Students();
So far I am lost on what to do.
Thanks
Dave

To implement as you ask, FileRoutines.LoadStudents(STUDENT_FILE) has to return a Students instance, so you need to modify that method to construct the new Students and return that instead of string[]
So perhaps your Students class takes the string[] in its constructor?
That should be enough to get you going?

Obviously, the Students type has to behave like a collection of some kind. I propose this
A class for a student data is a piece of cake.
class Student
{
public string Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Now things get a little more interesting. The following class implements IEnumerable of Student in order to provide the most crucial methods for looping through its inner structure. Is quite easy once you get this idea. You already store students in some collection so just return its enumerator instead of creating a custom one.
class Students : IEnumerable<Student>
{
private readonly List<Student> students;
public Students(IEnumerable<Student> students)
{
this.students = students.ToList();
}
public IEnumerator<Student> GetEnumerator()
{
return students.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return students.GetEnumerator();
}
}
And finally, a class with a method for loading from a file. This can be done many ways, but I find LINQ a nice tool for data querying.
class FileRoutines
{
public static Students LoadStudents(string path)
{
var lines = File.ReadLines(path);
var students = lines.Select(l => l.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries))
.Select(split => new Student
{
Id = split[0],
LastName = split[1],
FirstName = split[2]
});
return new Students(students);
}
}

Related

C# List.AsQueryable() returns System.Collections.Generic.List instead of IQueryable

I have a list of objects List<Student> that I want return as an IQueryable<Student>.
When I try to use .AsQueryable() on the list to convert it to IQueryable<Student> I got a System.Collections.Generic.List`1[ConsoleApp.Student].
How I can convert list to IQueryable()?
See below I minimum reproducible example:
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp
{
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
}
internal class Program
{
static void Main(string[] args)
{
var students = new List<Student>() ;
students.Add(new Student() { Id = 1, Name = "J" });
students.Add(new Student() { Id = 2, Name = "X" });
IQueryable<Student> queryable = students.AsQueryable();
Console.WriteLine("Hello, World!");
}
}
}
.AsQueryable() returns a EnumerableQuery<T> that wraps the list (or IEnumerable<T> to be precise) and provides the IQueryable interface. So if you just want an IQueryable<T> your don't need to do anything more. Your example already demonstrates this perfectly well.
Note that, the .ToString()-method on EnumerableQuery just seem to call the underlying collection, so it will still print {System.Collections.Generic.List1[ConsoleApp.Student]} in the debugger, or when converting it to string. I suspect this is why you are confused. You can call .GetType().Name to get the actual typename of an object.
The larger question is, why do you want a IQueryable? This is mostly intended to query databases. If you have objects in memory you usually just use IEnumerable<T>. If you just want to print your students, Overload .ToString on the student object and call string.Join to produce a string for all students.

C# method is not returning object - method chaining

I came across the post on stackoverflow that provided solution to question by chaining two methods. The answer looked something like this:
public x DoThis()
{
//do something
return this;
}
public x DoThat ()
{
//do something else
return this;
}
var x = new x ().DoThis().DoThat;
I read about chaining methods. But something does not seem to be right in this case. I created a class called Library with two different methods that return the same type, and I can access first of the methods, but not the second one. Unless, I'm doing something wrong, that solution is incorrect.
I watched tutorial on creating collection extention methods and I wanted to try use this approach. I have to admit that I do not understand everything about it yet. So I thought, I should be able to use IEnumerable<> because I'm only passing collection to this class
Here is a class:
class Library
{
private IEnumerable<Movie> MoviesLibrary;
public Library(IEnumerable<Movie> library)
{
this.MoviesLibrary = library.ToList();
}
public IEnumerable<Movie> FindMovie(int _movieId)
{
return this.MoviesLibrary.Where(movie => movie.MovieId == _movieId);
}
public IEnumerable<Movie> GetByYear(int _year)
{
return this.MoviesLibrary.Where(movie => movie.Year == _year);
}
}
As I understand "return this" statement should return currently instantiated object. In chained method, next method should use that returned object and perform its own action.
Can you provide more context for the first code example you gave?
(the one that doesn't work - for example what is X in your case? what class has the first method?).
The last example you gave
public IEnumerable<Movie> GetByYear(int _year)
{
this.MoviesLibrary.Where(movie => movie.MovieId == _movieId);
return this;
}
is incorrect because you return an IEnumerable,
and IEnumerable doesn't have the additional method which aren't extension methods.
Extension methods indeed may help you achieve what you want.
In fact, Linq is implemented as a set of extension methods to IEnumerable
See
https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,577032c8811e20d3
for more info (and examples how to write extension methods).
Also you may want to read more about extension method in their formal msdn page
https://msdn.microsoft.com/en-us/library/bb383977.aspx
This is a solution to my own question. I have to admit that it is not clear from the beginning what I was trying to accomplish, which is evident in the edit of the initial post. The first code example is answer to similar question posted by someone else on this site. It is very general in nature, however you can clearly see that this person is trying to advocate that it is possible to chain methods by returning the same object type. I wanted to accomplish something similar after watching tutorial called “Making Your C# Code More Object-Oriented” by Zoran Horvat. This tutorial is available on Pluralsight. His example is utilizing interfaces and extension methods in chapter 4 and 5. The idea for this solution is somewhat similar, but I wanted to have this functionality contained in a single class.
I think entire confusion is related to the type of the object that method needs to return in order to provide chaining functionality. Let’s take a look at some simple string example
someString.ToUpper.ToLower.Trim
The first thing that comes to our mind is that string is passed from one method to another method and at each step it is being modified by that method. Therefore we would have similar situation when working with collections.
movies.GetByYear(1999).GetByGroup(1).GetByGenre("Action")
In this case we start with some List that is being passed through this chain of methods. It is also very likely that we think that all methods in this chain operate on the same List. After all, string property from previous example is shared among all methods even though it is being modified. That’s not what actually happens with this collection of movies. Each method works with collection that has different size. It looks like GetByYear() and GetByGroup() are methods that work with the same list of movies, they are in fact separate Library objects that have completely different lists.
I would like to thank Sokohavi who left comment about returning Library object. He also suggests making Library object IEnumerable. Unfortunately, if you are thinking that method should return IEnumerable, than you are on the wrong path. Technically speaking Library is a List, but the list that holds Movie objects is set to private and is not visible to other objects. Therefore there is nothing to iterate through. Library object has only couple methods, and if you select one of them you will lose access to other methods in the same class. Therefore method must return Library object in order to gain access to all methods in the same class, and the list that stores Movie object must be IEnumerable. There is one drawback to this approach. You cannot load data to this list inside Library constructor. Instead data is passed as Parameter . Now you have objects that have different lists of movies and the way they communicate with each other is through their constructors.
Below we have Repository class that loads individual items into a list through its constructor. Library class defines methods that will provide filtering of the list that is being passed to it. You can also create another layer of abstraction that would use that functionality.
public class Movie
{
public string Title { get; set; }
public int Year { get; set; }
public int GroupId { get; set; }
public string Genre { get; set; }
}
public class Repository
{
private List<Movie> localDb;
public Repository()
{
localDb = new List<Movie>();
}
public IEnumerable<Movie> GetAllMovies()
{
localDb = new List<Movie>();
var movie1 = new Movie() { Title = "Movie1", Year = 2000, GroupId = 1, Genre = "Action" };
var movie2 = new Movie() { Title = "Movie2", Year = 1999, GroupId = 1, Genre = "Drama" };
var movie3 = new Movie() { Title = "Movie3", Year = 2000, GroupId = 1, Genre = "Comedy" };
var movie4 = new Movie() { Title = "Movie4", Year = 2000, GroupId = 2, Genre = "Action" };
var movie5 = new Movie() { Title = "Movie5", Year = 1999, GroupId = 2, Genre = "Drama" };
var movie6 = new Movie() { Title = "Movie6", Year = 1999, GroupId = 2, Genre = "Drama" };
var movie7 = new Movie() { Title = "Movie7", Year = 1999, GroupId = 2, Genre = "Horror" };
localDb.Add(movie1);
localDb.Add(movie2);
localDb.Add(movie3);
localDb.Add(movie4);
localDb.Add(movie5);
localDb.Add(movie6);
localDb.Add(movie7);
return localDb;
}
}
public class Library
{
private IEnumerable<Movie> MoviesLibrary;
public Library(IEnumerable<Movie> movies)
{
this.MoviesLibrary = movies.ToList();
}
public Library GetByYear(int year)
{
return new Library(this.MoviesLibrary.Where(movie => movie.Year == year));
}
public Library GetById(int id)
{
return new Library(this.MoviesLibrary.Where(movie => movie.GroupId == id));
}
public IEnumerable<Movie> GetByGenre(string genre)
{
return this.MoviesLibrary.Where(movie => movie.Genre == genre);
}
public void Display()
{
foreach (var movie in this.MoviesLibrary)
{
Console.WriteLine("Title: {0} , Year {1}, Group: {2}, Genre: {3}", movie.Title,movie.Year,movie.GroupId, movie.Genre);
}
}
}
How to use these classes:
var repository = new Repository();
var listOfMovies = repository.GetAllMovies();
var movies = new Library(listOfMovies);
var selectedMovies1 = movies.GetByYear(2000).GetById(1).GetByGenre("Action");
var selectedMovies2 = movies.GetByYear(2000).GetById(2);
foreach (var movie in selectedMovies1)
{
Console.WriteLine("Selected 1 - Title: {0} , Year {1}, Group: {2}, Genre: {3}", movie.Title,movie.Year,movie.GroupId, movie.Genre);
}
selectedMovies2.Display();
Output:
Selected 1 - Title: Movie1 , Year 2000, Group: 1, Genre: Action
Title: Movie4 , Year 2000, Group: 2, Genre: Action

Odd signature for a filter Func

I was asked a question yesterday that is throwing me for a loop. I was asked to implement the interface IPeopleFinder:
public interface IPeopleFinder
{
IEnumerable<Person> GetByAge(List<Person> people, int age);
IEnumerable<Person> Find<TType>(Func<IEnumerable<TType>, bool> filter);
}
on this class:
public class People
{
public List<Student> Students { get; }
public List<Teacher> Teachers { get; }
}
The first function is simple, but the second function I do not understand what it is trying to do:
IEnumerable<Person> Find<TType>(Func<IEnumerable<TType>, bool> filter);
The IEnumerable<TType> in the Func is what I do not understand. If the signuture was:
IEnumerable<Person> Find<TType>(Func<TType, bool> filter);
it would be a simple matter of passing the filter to the IEnumerable<T>.Where() function.
Could someone please explain how filter function accepting an IEnumerable<T> and returning a bool would work? I'm starting to think it is a typo and should be Func<TType, bool>.
Clarification on restraints:
Classes are defined thus:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public ushort Age { get; set; }
public Sex Sex { get; set; }
}
public class Student : Person
{
public Major Major { get; set; }
}
public class Teacher : Person
{
public Department Department { get; set; }
}
TType is restricted to be of type Person.
The way the question is written, once the Find method is implemented, it is to be used to find all Students majoring in a certain subject, and all Teachers belonging to a certain department.
Obviously the method should work for enumerations of enumerations such as
var l = new List<List<Student>>();
Now you can call myPeopleFinder.Find(x => x.Any()) which would return an enumeration of students.
A better example would be to filter those sub-lists from your enumeration that have a specific size:
myPeopleFinder.Find(x => x.Count() > 30)
EDIT: For a practical use-case imagine a school as a list of classes where every class itself has a list of Student and Teacher. Now you want to get all those classes that have more then a given amount (30 in my example) of Person (assuming that either Student and Teacher inherit from Person). Finally this method may flatten the resulting sub-lists into one single enumeration of type Person to get all the students and teachers within the overfull classes.
EDIT2: As you´re concerning to the properties of the persons instead of the list you should of course - as you´ve already assumed - use a Func<TType> with TType : Person. Seems like a type to me too.
I agree with your analysis and I wonder what kind of specification you got and from where.
The person who defined the IPeopleFinder interface should not only write code but also document it, at least in source code, better yet: describe the reason for the interface in a requirements document, define the context in a software architecture document and describe the detailed use in a design document.
As long as you only have the interface and no further description, just throw a NotImplementedException since it has not been defined that you should do something else.

C# Finding element in List of String Arrays

I cannot solve a problem for several hours now.
Here is a simplified scenario.
Let's say there is a list of people with their bids. I'm trying to find a person with the highest bid and return the name. I am able to find the highest bid, but how to I output the name?
List<String[]> list = new List<String[]>();
String[] Bob = { "Alice", "19.15" };
String[] Alice = {"Bob", "28.20"};
String[] Michael = { "Michael", "25.12" };
list.Add(Bob);
list.Add(Alice);
list.Add(Michael);
String result = list.Max(s => Double.Parse(s.ElementAt(1))).ToString();
System.Console.WriteLine(result);
As a result I get 28.20, which is correct, but I need to display "Bob" instead. There were so many combinations with list.Select(), but no success. Anyone please?
The best solution from an architectural point of view is to create a separate class (e.g. Person) that contains two properties Name and Bid of each person and a class Persons that contains the list of persons.
Then you can easily use a LINQ command.
Also instead of storing bids as string, think if bids as floating point or decimal values would be better (or store it in cents and use an int).
I don't have a compiler by hand so it's a bit out of my head:
public class Person
{
public string Name { get; set; }
public float Bid { get; set; }
public Person(string name, float bid)
{
Debug.AssertTrue(bid > 0.0);
Name = name;
Bid = bid;
}
}
public class Persons : List<Person>
{
public void Fill()
{
Add(new Person("Bob", 19.15));
Add(new Person("Alice" , 28.20));
Add(new Person("Michael", 25.12));
}
}
In your class:
var persons = new Persons();
persons.Fill();
var nameOfHighestBidder = persons.MaxBy(item => item.Bid).Name;
Console.WriteLine(nameOfHighestBidder);
This works in the simple example. Not sure about the real one
var result = list.OrderByDescending(s => Double.Parse(s.ElementAt(1))).First();
You can use Jon Skeet's MaxBy.
For usage you can see this question
e.g. in this case
list.MaxBy(s => Double.Parse(s.ElementAt(1)))[0]
More here
Should work:
var max = list.Max(t => double.Parse(t[1]));
list.First(s => double.Parse(s[1]) == max)[0]; // If list is not empty
After finding result just do as below:
list.First(x=>x[1] == result)[0]

LINQ - Help me grasp it with an example I think LINQ should be able to solve!

I am trying to get into LINQ to objects as I can see the power of it. Lucky enough I have a question that I think LINQ should be able to solve.
Here is the question (the details are an example);
public class SchoolClass
{
public int ID;
public string Name;
public string Teacher;
public string RoomName;
public string Student_Name;
public int Student_Age;
}
As you can see by the example, there is a one to many relationship between the ClassName, Teacher and Room and the Students, i.e. there are potentially many students in the one class.
If we have a List is it possible using LINQ to create a List but have only one instance ID, Name, Teacher, RoomName and an ArrayList of Student_Name and Age?
Producing this:
public class Students
{
public string Student_Name;
public int Student_Age;
}
public class SchoolClass
{
public int ID;
public string Name;
public string Teacher;
public string RoomName;
public ArrayList Students;
}
Essentially, using LINQ to clean the List to a more logical structure?
To give some background to this example. The second structure is used by a DataGrid to produce a Master-Child relationship. We store SchoolClass and StudentInformation in classes as shown above. It would be good use of LINQ to be able to convert our initial List into a structure which can be used by the DataGrid.
I changed the ArrayList to List<Students>, and:
List<SourceData> source = new List<SourceData>();
//...your data here ;-p
var classes = (from row in source
group row by new {
row.ID, row.Name,
row.Teacher, row.RoomName }
into grp
select new SchoolClass
{
ID = grp.Key.ID,
Name = grp.Key.Name,
Teacher = grp.Key.Teacher,
RoomName = grp.Key.RoomName,
Students = new List<Students>(
from row in grp
select new Students
{
Student_Age = row.Student_Age,
Student_Name = row.Student_Name
})
}).ToList();
If I'm understanding this correctly, I would've thought the best way to implement the SchoolClass class would be to create a Student class (probably a LINQ-to-SQL entity, if you're using it) and to have a generic list of type student, something similar to this:
public class SchoolClass
{
public int ID;
public string Name;
public string Teacher;
public string RoomName;
public List<Student> Students;
}
The list of students could then be populated using a linq query, although I'm not sure exactly how without more information.
Hope this is some help.

Categories