问题
I'm having Two models Person and Boss. Boss is derived from Person. Here the property ID and SID both are speaking about the Employee ID. The ID Speaks about the Boss and SID speaks about the Assistant Staff.
Kindly refer the Model Classes and the Collection
public class Person
{
public int ID { get; set; }
public int SID { get; set; }
public string Name { get; set; }
public string Department { get; set; }
public string Gender { get; set; }
public string Role { get; set; }
}
public class Boss
{
public int ID { get; set; }
public int SID { get; set; }
public string Name { get; set; }
public string Department { get; set; }
public string Gender { get; set; }
public string Role { get; set; }
public List<Person> Employees { get; set; }
}
void Main()
{
List<Boss> BossList = new List<Boss>()
{
new Boss()
{
ID = 101,
Name = "Harry",
Department = "Development",
Gender = "Male",
Role = "Manager",
Employees = new List<Person>()
{
new Person() {ID = 101, SID = 102, Name = "Peter", Department = "Development", Gender = "Male", Role = "Assistant"},
new Person() {ID = 101, SID = 103, Name = "Emma Watson", Department = "Development", Gender = "Female", Role = "Assistant"},
}
},
new Boss()
{
ID = 104,
Name = "Raj",
Department = "Development",
Gender = "Male",
Role = "Manager",
Employees = new List<Person>()
{
new Person() {ID = 104, SID = 105, Name = "Kaliya", Department = "Development", Gender = "Male", Role = "Assistant"},
new Person() {ID = 104, SID = 103, Name = "Emma Watson", Department = "Development", Gender = "Female", Role = "Assistant"},
}
},
new Boss()
{
ID = 102,
Name = "Peter",
Department = "Development",
Gender = "Male",
Role = "Manager",
Employees = new List<Person>()
{
new Person() {ID = 102, SID = 105, Name = "Kaliya", Department = "Development", Gender = "Male", Role = "Assistant"},
new Person() {ID = 102, SID = 103, Name = "Emma Watson", Department = "Development", Gender = "Female", Role = "Assistant"},
}
}
};
}
My Required Collection should be
List<Person> Members = new List<Person>()
{
new Person() {Name = "Harry", Department = "Development", Gender = "Male", Role = "Manager"},
new Person() {Name = "Peter", Department = "Development", Gender = "Male", Role = "Manager"},
new Person() {Name = "Emma Watson", Department = "Development", Gender = "Female", Role = "Assistant"},
new Person() {Name = "Raj", Department = "Development", Gender = "Male", Role = "Manager"},
new Person() {Name = "Kaliya", Department = "Development", Gender = "Male", Role = "Assistant"},
}
Here My Requirement is I need to make the Distinct list of Employees including Boss. But the Distinct list contains Peter has an unique ID 102 in both Boss as well as in Assistant Staff, but here I need to select the Manager Role not a Assistant Role record.
Kindly assist me how to achieve this. Kindly provide your answer instead on suggestions to change the Model structure or any other suggestions.
Explanation of ID and SID:
- ID : It has an Employee ID of Boss
- SID : It has an Employee ID of Assistant
The Collection - Role is marked as Manager, then he/she don't have an SID, because he is a Boss (or) Manager. He/She is the Superior so the Employee ID is assigned in ID. In other case Role is marked as Assistant, then he/she is under any one of the Boss (or) Manager. So, the ID is marked with the Manager ID and the actual Employee ID is marked in SID.
回答1:
The first thing to do is to create custom IEqualityComparer<Person>
class which will be used as Distinct
argument.
Edit #2: taking into account role
public class PersonEqualityComparer : IEqualityComparer<Person>
{
public bool Equals(Person x, Person y)
{
if(x == null && y == null) return true;
int xid = x.Role == "Manager" ? x.ID : x.SID;
int yid = y.Role == "Manager" ? y.ID : y.SID;
return xid == yid;
}
public int GetHashCode(Person obj)
{
return obj.Role == "Manager" ? obj.ID : obj.SID;
}
}
Then you can write this:
// take employees first
var personList = BossList.SelectMany(x => x.Employees).ToList();
// add bosses to list
personList.AddRange(BossList.AsEnumerable());
// take distinct persons
var result = personList.Distinct(new PersonEqualityComparer()).ToList();
I have noticed some issues with your code:
SID = "Emma Watson"
is used twice. I assume that something likeSID = 103, Name = "Emma Watson"
was intended.- You've said that Boss is derived from Person, however code does not stick with this statement. I assume
Boss : Person
should be written and duplicate fields should be omitted.
Edit:
If it is possible kindly give your answer in a single inline LINQ Statement.
var result = BossList.SelectMany(x => x.Employees)
.Union(BossList.AsEnumerable())
.Distinct(new PersonEqualityComparer())
.ToList();
Still you need to have PersonEqualityComparer
code.
Edit #3
var personList = BossList.SelectMany(x => x.Employees).Union(BossList.AsEnumerable()).ToList();
var ids = personList.Select(x => x.Role == "Manager" ? x.ID : x.SID).Distinct().ToList();
var result = ids.GroupJoin(personList, id => id, person => person.Role == "Manager" ? person.ID : person.SID,
(id, persons) =>
persons.OrderBy(p => p.Role == "Manager" ? 0 : 1).First()).ToList();
来源:https://stackoverflow.com/questions/36068060/how-to-group-by-make-distinct-from-two-properties-has-same-entity-in-c-sharp-lin