Reputation: 485
i need to sort a list by a hierarchy, can someone give me a hand? The list looks like this:
// create your list
List<Person> persons = new List<Person>();
// populate it
persons.Add(new Person("child", "father"));
persons.Add(new Person("father", "grandfather"));
persons.Add(new Person("grandfather", "grandgrandfather"));
persons.Add(new Person("grandgrandfather", null));
I want something like:
I've tryed to implement IComparable in my classe "Person", like this:
public class Person : IComparable<Person>
{
public String ID { get; set; }
public String ParentID { get; set; }
public Person(String id, String pid)
{
this.ID = id;
this.ParentID = pid;
}
public Int32 CompareTo(Person right)
{
if (this.ID.Equals(right.ID))
return 0;
if (this.ParentID == null) return -1;
if (right.ParentID == null) return 1;
return this.ParentID.CompareTo(right.ID);
}
}
but it isn't doing the thing...
Upvotes: 1
Views: 4105
Reputation: 62940
You need to compute the dept of items in the hierarchy, and sort the list by dept:
If the following is the person class:
class Person
{
public string Name {get; private set;}
public string Parent {get; private set;}
public Person(string name, string parent)
{
this.Name = name;
this.Parent = parent;
}
}
This is an example of a method that computes the dept of a person in the hierarchy.
int GetDept(List<Person> list, Person person)
{
if (person.Parent == null) return 0;
return GetDept(list, list.First(p => p.Name == person.Parent)) + 1;
}
Then the method can be used to sort the list by dept
List<Person> persons = new List<Person>();
// populate it
persons.Add(new Person("child", "father"));
persons.Add(new Person("father", "grandfather"));
persons.Add(new Person("grandfather", "grandgrandfather"));
persons.Add(new Person("grandgrandfather", null));
var sorted = persons.OrderBy(p => GetDept(persons, p));
foreach(var person in sorded)
Console.WriteLine("{0} {1} {2}", person.Name, person.Parent, GetDept(persons, p))
This will print:
grandgrandfather null 0
grandfather grandgrandfather 1
father grandfather 2
child father 3
Note that in this example the dept is not computed efficiently as the GetDept
method will get itself called again and again and also it uses O(n) lookup over a list. All these can be improved by computing the dept only once for each person and storing it, combined with a more efficient look up mechanism like a dictionary in order to get good performance for large data sets.
Upvotes: 6
Reputation: 19897
Your problem is that you don't have a way to determine which is greater if the values are spread too far apart. For example: Your grandfather and child elements will always return -1 since the string "father" is always less than the string "grandfather". Try making your person values into constant int values and then comparing like this:
const int child = 0;
const int father = 1;
const int grandfather = 2;
const int greatgrandfather = 3;
// create your list
List<Person> persons = new List<Person>();
// populate it
persons.Add(new Person(child));
persons.Add(new Person(father));
persons.Add(new Person(grandfather));
persons.Add(new Person(grandgrandfather));
public class Person : IComparable<Person>
{
public int ID { get; set; }
public Person(int id)
{
this.ID = id;
}
public Int32 CompareTo(Person right)
{
if (this.ID == right.ID)
return 0;
if (this.ID > right.ID) return -1;
else return 1;
}
}
Upvotes: 1
Reputation: 44931
This is a data problem. You are trying to compare string values, but there is nothing inherent in your data that provides relative relationships.
I would suggest that you convert your values to an Enum, which could then be easily compared. Here is some pseudo-code that I have not tested, but which should give you an idea:
public class Person : IComparable<Person>
{
public enum Types: int {
None,
Child,
Father,
Grandfather,
GrandGrandFather
}
public Types ID { get; set; }
public Types ParentID { get; set; }
public Person(Types id, Types pid)
{
this.ID = id;
this.ParentID = pid;
}
public Int32 CompareTo(Person right)
{
return this.ParentID.CompareTo(right.ID);
}
}
Upvotes: 0
Reputation: 5958
You have to modify the logic of your public int CompareTo(Person right)
method according to your sorting logic.
For example
if (this.ID == grandgrandfather &&
right.ID == grandfather) return 1;
if (this.ID == grandgrandfather &&
right.ID == child) return 1;
....... a lot more
Upvotes: 0