Simon
Simon

Reputation: 8357

How can I sort a list that has potential parents with the parent objects first in the list?

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

Answers (4)

Fabjan
Fabjan

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

Shar1er80
Shar1er80

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

Fiddle Demo

Upvotes: 1

Vernard Sloggett
Vernard Sloggett

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

Christos
Christos

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

Related Questions