Reputation: 8357
In C#, if I have a list of objects, where each object can have a parent, and each parent can have a parent (x combinations), how is the best way to sort the list so that all the parent objects are first in the list?
Here is the object structure:
class test
{
int id { get; set; }
int parentId { get; set; }
bool hasParentObject { get; set; }
}
Here is an example of some objects:
Object a:
id = 1;
parentId = 0;
hasParentObject = false;
Object b:
id = 2;
parentId = 1;
hasParentObject = true;
Object c:
id = 3;
parentId = 2;
hasParentObject = true;
Thanks.
EDIT
With the following code, how can the code be modified so that if an object does not have a parent, the object is in the list before any objects that do have parents?
Code:
class Test : IComparable<Test>
{
public int Id { get; set; }
public int ParentId { get; set; }
public bool HasParentObject { get; set; }
public int CompareTo(Test other)
{
if(!this.HasParentObject)
return 1;
else if(!other.HasParentObject)
return 1;
else if(other.HasParentObject && this.HasParentObject)
return ParentId.CompareTo(other.ParentId);
else if(other.HasParentObject)
return 1;
else
return -1;
}
}
Upvotes: 0
Views: 435
Reputation: 13676
You can use new Comparison overload of Sort method - .Sort(new Comparison<test>(expression))
For instance :
List<test> list = new List<test>()
{
new test() { id=1, hasParentObject = false, parentId = 0 },
new test() { id=2, hasParentObject = true, parentId = 1 },
new test() { id=3, hasParentObject = false, parentId = 0 },
new test() { id=4, hasParentObject = true, parentId = 3 },
};
list.Sort((s1, s2) => s1.parentId > s2.parentId ? 1 : (s1.parentId < s2.parentId ? -1 : 0));
foreach (var item in list)
Console.WriteLine(item.id);
Console.ReadKey();
Upvotes: 0
Reputation: 9041
It sounds like you would want the objects that are parents first in the list (Optional: Ordered by ID), then you want the objects that aren't parents to follow the parent objects in the list (Optional: Ordered by ID).
This isn't a one liner, but I think it does what you're asking
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
List<Test> tests = new List<Test>
{
new Test() { Id = 6, ParentId = 2, HasParentObject = true },
new Test() { Id = 2, ParentId = 0, HasParentObject = false },
new Test() { Id = 1, ParentId = 0, HasParentObject = true },
new Test() { Id = 4, ParentId = 1, HasParentObject = true }
};
// Get the parents sorted
List<Test> sortedTests = tests.Where(t => tests.FindIndex(t2 => t2.ParentId == t.Id) != -1)
.OrderBy(t => t.Id)
.ToList();
// Add those that aren't parents sorted
sortedTests.AddRange(tests.Where(t => tests.FindIndex(t2 => t2.ParentId == t.Id) == -1)
.OrderBy(t => t.Id));
sortedTests.ForEach(t => Console.WriteLine("ID: {0} ParentId: {1}", t.Id, t.ParentId));
}
}
class Test
{
public int Id { get; set; }
public int ParentId { get; set; }
public bool HasParentObject { get; set; }
}
Results:
ID: 1 ParentId: 0
ID: 2 ParentId: 0
ID: 4 ParentId: 1
ID: 6 ParentId: 2
Upvotes: 1
Reputation: 334
if one can assume the hasParentObject property is public
public List<test> l;
public List<test> sortList(List<test> _l)
{
return _l.OrderByDescending(a => a.hasParentObject).ToList();
}
Upvotes: 0
Reputation: 53958
You could implement the IComparable
itherface for your class and then use the Sort
method of the list.
class Test : IComparable<Test>
{
public int Id { get; set; }
public int ParentId { get; set; }
public bool HasParentObject { get; set; }
public int CompareTo(Test other)
{
if(other.HasParentObject && this.HasParentObject)
return ParentId.CompareTo(other.ParentId);
else if(other.HasParentObject)
return 1;
else
return -1;
}
}
Please look here for a working example based on your post's data.
Upvotes: 0