I have a c# project, and I've created a class called Employees.
Inside this class, I have a new list:
public class Employees
{
public int Id { get; set; }
public string Name { get; set; }
public int? ManagerId { get; set; }
public List<Employees> employees { get; set; }
}
Imagine that I have the following structure shown in the image:
companytree
Then in the main program, I have this structure to represent the picture above:
class Program
{
static void Main(string[] args)
{
var root = new Employees()
{
Id = 15,
Name = "President",
employees = new List<Employees>()
{
new Employees() {
Id = 23, ManagerId = 15, Name = "Director23",
employees = new List<Employees>()
{
new Employees() {
Id = 21, ManagerId = 23, Name = "Manager21",
employees = new List<Employees>()
{
new Employees() { Id = 31, ManagerId=21, Name = "Employee31" },
new Employees() { Id = 41, ManagerId=21, Name = "Employee41" },
new Employees() { Id = 51, ManagerId=21, Name = "Employee51" }
}
},
new Employees() {
Id = 22, ManagerId = 23, Name = "Manager22",
employees = new List<Employees>()
{
new Employees() { Id = 32, ManagerId=22, Name = "Employee32" },
new Employees() { Id = 42, ManagerId=22, Name = "Employee42" },
new Employees() { Id = 52, ManagerId=22, Name = "Employee52" }
}
}
}
},
new Employees() {
Id = 25, ManagerId = 15, Name = "Director25",
employees = new List<Employees>()
{
new Employees() {
Id = 51, ManagerId = 25, Name = "Manager51",
employees = new List<Employees>()
{
new Employees() { Id = 61, ManagerId=51, Name = "Employee61" },
new Employees() { Id = 71, ManagerId=51, Name = "Employee71" },
new Employees() { Id = 81, ManagerId=51, Name = "Employee81" }
}
},
new Employees() {
Id = 62, ManagerId = 25, Name = "Manager62",
employees = new List<Employees>()
{
new Employees() { Id = 72, ManagerId=62, Name = "Employee72" },
new Employees() { Id = 82, ManagerId=62, Name = "Employee82" }
}
}
}
}
}
};
Console.ReadLine();
}
}
How to create a function where I pass the tree root list of the employee and the ID of any employee of the company and you need to return your manager closer or higher and also the employee itself.
Remembering that you could pass the ID of a director (you would have to return the president), the ID of the manager(you would have to return the director), the ID of the employee (you would have to return the manager), the ID of the presidente return himself.
What better way to do this research taking into account that we can have a much larger hierarchical structure than this example. It would be costly to scan all lists.
Use hastable, dictionary, hashset??
A recursive function is generally used to search a tree. I assumed you fix the variable names as suggested:
public static Employee FindById(Employee root, int id) {
if (root.Id == id)
return root;
else if (root.Employees != null) {
foreach (var e in root.Employees) {
var pe = FindById(e, id);
if (pe != null)
return pe;
}
}
return null;
}
To use, find the employee and then the manager:
var emp = FindById(root, 51);
var manager = emp.ManagerId.HasValue ? FindById(root, emp.ManagerId.Value) : null;
Add there two functions :
public static IDictionary<int, Employees> EmployeesToDictionary(Employees employees)
{
var dictionary = new Dictionary<int, Employees>();
EmployeesToDictionary(employees, dictionary);
return dictionary;
}
private static void EmployeesToDictionary(Employees employees, IDictionary<int, Employees> dictionary)
{
if (employees == null) return;
dictionary.Add(employees.Id, employees);
if (employees.employees == null) return;
foreach (var sub in employees.employees)
{
EmployeesToDictionary(sub);
}
}
And usage :
var id = 5;
var dict = EmployeesToDictionary(root);
var employee = dict[id];
var manager = dict[employee.ManagerId.Value];
Edit :
#haindl Documentation is an admission of failure Yeah you're right.
#devweb I have added the check for the exception. The dictionnary is created only one time, check again
If you want to do a traversal only once, there are this possibility :
public static void FindById(Employees root, int id, out Employees employees, out Employees manager)
{
employees = manager = null;
// todo stack
var stack = new Stack<Employees>();
stack.Push(root);
// all managers seens
var managers = new List<Employees>();
while (stack.Count > 0)
{
var e = stack.Pop();
if (e.Id == id) // if found
{
employees = e;
manager = managers.FirstOrDefault(m => m.Id == e.ManagerId);
return;
}
else if (e.employees != null)
{
// add only managers with employee
managers.Add(e);
foreach (var ep in e.employees)
{
stack.Push(ep);
}
}
}
}
Related
I'm currently working on a .NET 4.7 application. I need to create a tree structure out of unsorted data.
The final tree structure looks like this:
public class LocationViewModel
{
public int Id { get; set; }
public string Code { get; set; }
public List<LocationViewModel> ChildLocations { get; set; }
}
One Parent LocationViewModel can have several ChildLocations. Each ChildLocation can have several ChildLocations itself again.
I need to sort the data from the following structure. My unsorted data is a List<LinkParentChildViewModel> LinksParentChild, and looks like this:
public class LinkParentChildViewModel
{
public Location Parent { get; set; }
public LocationLink Child { get; set; }
}
public class Location
{
public int Id { get; set; }
public string Code { get; set; }
}
public class LocationLink
{
public int ParentLocationId { get; set; }
public int ChildLocationId { get; set; }
}
First I have a List<Location> Locations, which contains all the locations.
Then I'm getting a List<LinkParentChildViewModel> LinksParentChild, the entries are all mixed up - thus a Parent can be a child and a child can be a parent.
var LinksParentChild = new List<LinkParentChildViewModel>
{
new LinkParentChildViewModel
{
Parent = new Location
{
Id = 8,
Code = "ParLoc1",
},
Child = new LocationLink
{
ChildLocationId = 4,
ParentLocationId = null
}
},
new LinkParentChildViewModel
{
Parent = new Location
{
Id = 4,
Code = "Loc1",
},
Child = new LocationLink
{
ChildLocationId = 6,
ParentLocationId = 8
}
},
new LinkParentChildViewModel
{
Parent = new Location
{
Id = 6,
Code = "ChildLoc1",
},
Child = new LocationLink
{
ChildLocationId = null,
ParentLocationId = 4
}
},
new LinkParentChildViewModel
{
Parent = new Location
{
Id = 10,
Code = "LeftLoc1",
},
Child = new LocationLink
{
ChildLocationId = 11,
ParentLocationId = 4
}
},
new LinkParentChildViewModel
{
Parent = new Location
{
Id = 11,
Code = "LeftChildLoc1",
},
Child = new LocationLink
{
ChildLocationId = null,
ParentLocationId = 10
}
}
};
I need to write a LINQ query to group all nodes from my data into a List<LocationViewModel> result.
var result = LinksParentChild.GroupBy(x => x.Parent.Id).Select(x => new LocationViewModel
{
Id = x.First().Parent.Id,
Code = x.First().Parent.Code,
ChildLocations = new List<LocationViewModel>
{
// ... I'm stuck unfortunately, somehow i need to query and group all locations
}
}).ToList();
I tried, but unfortunately I'm stuck:
I need to select all Locations like a tree structure
Do you know how to solve this issue?
Thanks a lot!
The result looks like this:
var result = new List<LocationViewModel>
{
new LocationViewModel
{
Id = 8,
Code = "ParLoc1",
ChildLocations = new List<LocationViewModel>
{
new LocationViewModel
{
Id = 4,
Code = "Loc1",
ChildLocations = new List<LocationViewModel>
{
new LocationViewModel
{
Id = 6,
Code = "ChildLoc1"
},
new LocationViewModel
{
Id = 10,
Code = "LeftLoc1",
ChildLocations = new List<LocationViewModel>
{
new LocationViewModel
{
Id = 11,
Code = "LeftChildLoc1"
}
}
}
}
}
}
}
};
you can try with Recursion
public static List<LocationViewModel> GetHierarchy(List<LinkParentChildViewModel> linkParentChildViewModels, int parentId)
{
return linkParentChildViewModels.Where(x => x.Parent.Id == parentId).Select(x => new LocationViewModel
{
Id = x.Parent.Id,
Code = x.Parent.Code,
ChildLocations = GetHierarchy(linkParentChildViewModels, x.Child.ChildLocationId)
}).ToList();
}
Call this from Main method
var result = GetHierarchy(LinksParentChild, 8);
how can I get N elements of the child list? Let's say I'd like to get 2 children for each parent.
public class Program
{
static void Main(string[] args)
{
var data = new List<Parent>()
{
new Parent()
{
Id = 1,
Name = "ParentName1",
Children = new List<Child>()
{
new Child() { Id = 1, Name = "ChildName1"},
new Child() { Id = 2, Name = "ChildName2"},
new Child() { Id = 3, Name = "ChildName3"},
new Child() { Id = 4, Name = "ChildName4"},
new Child() { Id = 5, Name = "ChildName5"},
}
},
new Parent()
{
Id = 2,
Name = "ParentName2",
Children = new List<Child>()
{
new Child() { Id = 6, Name = "ChildName6"},
new Child() { Id = 7, Name = "ChildName7"},
new Child() { Id = 8, Name = "ChildName8"},
new Child() { Id = 9, Name = "ChildName9"},
new Child() { Id = 10, Name = "ChildName10"},
}
}
};
// Get only 2 child elements for parent
var filteredData = data.Where(x => x.Children.Count >= 2)
.ToList();
foreach (var filteredParent in filteredData)
{
Console.WriteLine($"Parent {filteredParent.Id} with {filteredParent.Children.Count} children.");
}
Console.ReadKey();
}
}
public class Parent
{
public int Id { get; set; }
public string Name { get; set; }
public List<Child> Children { get; set; }
}
public class Child
{
public int Id { get; set; }
public string Name { get; set; }
public Parent Parent { get; set; }
}
One way to do it is to use a multi statement lambda expression for the result selector and List<T>'s RemoveRange method:
var query = data.Select
(
p =>
{
p.Children.RemoveRange(2, p.Children.Count - 2);
return p;
}
);
As Flater commented, It might be better to return a shallow copy of the parent, with only the first two children. That way your query does not change the source data:
var query = data.Select
(
p => new Parent()
{
Id = p.Id,
Name = p.Name,
Children = p.Children.Take(2).ToList()
}
);
Given these classes:
public class Employee
{
public int EmployeeId { get; set; }
public int GroupId { get; set; }
public List<Plans> Plans { get; set; }
}
public class Plan
{
public int PlanYearId { get; set; }
public string Name { get; set; }
}
And given a setup like so:
var employees = new List<Employee> {
new Employee {
EmployeeId = 1,
GroupId = 1,
Plans = new List<Plan> {
new Plan {
PlanReferenceId = 1111,
Name = "Benefit 1"
}}};
new Employee {
EmployeeId = 1,
GroupId = 1,
Plans = new List<Plan> {
new Plan {
PlanReferenceId= 2222,
Name = "Benefit 2"
},
new Plan {
PlanReferenceId= 2222,
Name = "Benefit 3"
}}}};
How can I use LINQ to group these employees by both EmployeeId and GroupId and then combine the two List<Plan> properties so that i would end up with something like this:
var employee = new Employee
{
EmployeeId = 1,
GroupId = 1,
Plans = new List<Plan> {
new Plan {
PlanReferenceId = 1111,
Name = "Benefit 1"
},
new Plan {
PlanReferenceId = 2222,
Name = "Benefit 2"
},
new Plan {
PlanReferenceId = 2222,
Name = "Benefit 3"
}
}
}
Just use combination of GroupBy and SelectMany:
var result = employees
.GroupBy(e => new { e.EmployeeId, e.GroupId })
.Select(g => new Employee
{
EmployeeId = g.Key.EmployeeId,
GroupId = g.Key.GroupId,
Plans = g.SelectMany(e => e.Plans).ToList()
}).ToList();
I have a dataset: List<school> schools. I want to print the data in a form of output tree.
How to group the values by id, to display in this format:
-Department
--Education
---District
----Public Schools
-----School1
-----School4
----Private Schools
-----College5
-----College3
-----College2
List<school> Schools = new List<school>()
{
new school() { id = 1, Description = "Department", ParentID = null},
new school() { id = 2, Description = "Education", ParentID = 1},
new school() { id = 3, Description = "District", ParentID = 2},
new school() { id = 4, Description = "Public Schools", ParentID = 3},
new school() { id = 5, Description = "College2", ParentID = 6},
new school() { id = 6, Description = "Private Schools", ParentID = 3},
new school() { id = 7, Description = "School4", ParentID = 4},
new school() { id = 8, Description = "College5", ParentID = 6},
new school() { id = 9, Description = "School1", ParentID = 4},
new school() { id = 9, Description = "College3", ParentID = 6}
};
foreach(var _school in Schools)
{
if(_school.ParentID != null)
{
for (int i = 0; i < Schools.Count; i++)
{
IEnumerable<school> query = Schools.Where(s => s.ParentID + i == s.ID);
var dash = "-";
foreach (var school in query)
{
dash += dash;
Console.WriteLine( dash + t.Description);
}
};
}
else
{
Console.WriteLine("-" + _school.Description);
};
};
You can do something like this, using a recursive method:
In your main function:
var root = schools.SingleOrDefault(x => x.ParentID == null);
if(root != null) {
PrintSub(schools, root, 1);
}
And a (static) recursive function:
private static void PrintSub(List<School> schools, School current, int level)
{
Console.WriteLine(new string('-', level) + current.Description);
var children = schools.Where(x => x.ParentID == current.id);
++level;
foreach (var school in children)
{
PrintSub(schools, school, level);
}
}
With your data structure algorithm must be like next:
public void Print(List<school> nodes, int? parentId, string prefix)
{
var nodesToPrint = nodes.Where(x => x.ParentID == parentId);
foreach (var item in nodesToPrint)
{
Console.WriteLine(prefix + item.Description);
Print(nodes, item.id, prefix + prefix[0]);
}
}
And print it from code as:
Print(Schools, null, "-");
But I want to suggest you to store your tree as logical tree.
For example:
public class school
{
public string Description { get; set; }
public List<school> Childs { get; set; }
}
with printing method inside this class:
public void Print(string prefix = string.Empty)
{
Console.WriteLine(prefix + this.Description);
if (this.Childs != null)
{
foreach (var item in this.Childs)
{
item.Print(prefix + "-");
}
}
}
So if you will have only one parent item, you could print whole tree like this:
var sch = //your method to get schools
sch.Print();
suppose that I have this List of Employees representing a table of employees.
public class Employee
{
public string Name { get; set; }
public string Department { get; set; }
public string Function { get; set; }
public decimal Salary { get; set; }
public DateTime EntryDate { get; set; }
public static List<Employee> GetEmployeesList()
{
return new List<Employee>() {
new Employee() { EntryDate = new DateTime(2011, 05, 01), Name = "Fons", Department = "Finance", Function = "Trader", Salary = 6500 },
new Employee() { EntryDate = new DateTime(2013, 05, 02), Name = "Mary", Department = "Finance", Function = "BusinessAnalyst", Salary = 2500 },
new Employee() { EntryDate = new DateTime(2012, 04, 03), Name = "Alex", Department = "Finance", Function = "Trader", Salary = 2100 },
new Employee() { EntryDate = new DateTime(2013, 05, 04), Name = "Jim", Department = "R&D", Function = "Trainer", Salary = 3300 },
new Employee() { EntryDate = new DateTime(2010, 06, 05), Name = "Ellen", Department = "Dev", Function = "Developer", Salary = 2500 },
new Employee() { EntryDate = new DateTime(2000, 09, 06), Name = "Mike", Department = "Dev", Function = "Consultant", Salary = 5100 },
new Employee() { EntryDate = new DateTime(1999, 03, 07), Name = "Jack", Department = "R&D", Function = "Developer", Salary = 6100 },
new Employee() { EntryDate = new DateTime(1989, 01, 08), Name = "Demy", Department = "Dev", Function = "Consultant", Salary = 3300 }};
}
}
I want to be able to select only desired columns to be displayed.
Someting like :
public static List<Employee> SelectColumnsFromTable(List<Employee> employees, int[] selectedColumns)
{
// only select colums 1, 3 and 4
}
I have seen that it is possible with SQL and GridView, but in my case, the result will be printed on the console.
Is it possible using C# and Linq ?
As I understand the question, it is important to select specific properties of a class based on their index. If the relevant indices are provided to you by the user, you can use reflection to access the properties dynamically. The key points are Type.GetProperties and PropertyInfo.GetValue. I've put together a small sample to demonstrate:
using System;
using System.Collections.Generic;
using System.Linq;
public class Employee
{
public int Id {get; set;}
public string FirstName { get; set;}
public string LastName {get; set;}
}
public class Test
{
private static string[] GetColumnValues(Employee emp, params int[] cols)
{
var props = emp.GetType().GetProperties();
var values = new List<string>();
foreach(var i in cols)
{
if (i >= 0 && i < props.Length)
{
object value = props[i].GetValue(emp, null);
values.Add(value == null ? string.Empty : value.ToString());
}
}
return values.ToArray();
}
public static void Main()
{
var emp = new Employee() { Id = 1, FirstName = "John", LastName = "Smith" };
var values = GetColumnValues(emp, 0, 2);
Console.WriteLine(string.Join("\t", values));
}
}
Please note that referencing the properties by their index might not be very deterministic of you change the implementation later on. So selecting by the property's name might be more stable. Also, the column selector function GetColumnValues does not return Employees, but the values as a string array so you can use it in String.Join. You can use the function in Linq:
var rows = from x in listOfEmps select GetColumnValues(x, 0, 2);
foreach(var row in rows)
Console.WriteLine(string.Join("\t", row));
var items = (from i in v.db.DatabaseName
orderby i.EmpID descending
select new {i.Name, i.Function,i.Salary}).ToList();
var list = dt.AsEnumerable()
.Where(row => (int)row["demoid"] > 5)//your condition here
.Select(row => new
{
demoid = Convert.ToInt32(row["demoid"]),
demoname = row["demoname"] != null ?
row["demoname"].ToString() :
String.Empty
}).ToList();
Or you can define class:
public class myClass
{
public int demoid;
public string demoname;
}
and then:
List<myClass> list = dt.AsEnumerable()
.Where(row => (int)row["demoid"] > 5)
.Select(row => new myClass
{
demoid = Convert.ToInt32(row["demoid"]),
demoname = row["demoname"] != null ?
row["demoname"].ToString() :
String.Empty
}).ToList<myClass>();
this is selecting a particular value to a list. However you can use IList<myClass> classcollection= new List<myClass>(); and then add the particular list to class1 based on condition.
Note: here class collection can hold multiple list as u want the columns 1,3,4