Percy
Percy

Reputation: 3115

Sorting a list by parent/child relations ship so I have definitely processed a parent before I try to process the child

I have a system where people can sent me a List<ProductCategory>.

I need to do some mapping to my system and then save these to the database.

The incoming data is in this format:

public string ExternalCategoryID { get; set; }
public string ExternalCategoryName { get; set; }
public string ExternalCategoryParentID { get; set; }

The incoming list is in no particular order. If ExternalCategoryParentID is null then this is a top level category. The parent child relationship can be any depth - i.e. Technology > TVs > Samsung > 3D > 40" > etc > etc

When I'm saving I need to ensure I've already saved the parent - I can't save TVs until I have saved Technology. The ExternalCategoryID is likely to be an int but this has no relevance on the parent child relationship (a parent can have a higher or lower id than a child).

How can I order this list so I can loop through it and be certain that for any child, I have already processed it's parent.

The only way I can think of is to get all where ExternalCategoryParentID == null then get all where the ExternalCategoryParentID is in this "Top Level" list, then get the next set of children... etc. but this can't be the best solution. I'd prefer to sort first, then have a single loop to process. I have found this post, but it relies on createdDate which isn't relevant to me.

Upvotes: 0

Views: 1535

Answers (2)

Percy
Percy

Reputation: 3115

Turns out it wasn't so difficult after all. I wrote this function to do it - you pass in the original list and it will return a sorted list.

It works by looping through the list checking if there are any items in the list that have id == current items parentid. If there is one, we ignore that item and continue. if there aren't any, we add the current item to the sortedList and remove it from the original list and continue. This ensures that items are inserted in the sorted list after their parent.

private List<HeisenbergProdMarketplaceCategory> SortByParentChildRelationship(List<HeisenbergProdMarketplaceCategory> heisenbergMarketplaceCategories)
{
    List<HeisenbergProdMarketplaceCategory> sortedList = new List<HeisenbergProdMarketplaceCategory>();

    //we can check that a category doesn't have a parent in the same list - if it does, leave it and continue
    //eventually the list will be empty
    while(heisenbergMarketplaceCategories.Count > 0)
    {
        for (int i = heisenbergMarketplaceCategories.Count-1; i >= 0; i--)
        {
            if (heisenbergMarketplaceCategories.SingleOrDefault(p => p.ExternalCategoryID == heisenbergMarketplaceCategories[i].ExternalCategoryParentID) == null)
            {
                sortedList.Add(heisenbergMarketplaceCategories[i]);
                heisenbergMarketplaceCategories.RemoveAt(i);
            }
        }
    }

    return sortedList;
}

Upvotes: 1

FakeisMe
FakeisMe

Reputation: 464

We can check the field value to be null and then set int.max to it and then order by desc to get it at the top.

We can check the ExternalCategoryID = field.Value ?? int.max and then Order by descending.

Sample :

var query = context.Categories.Select(o => new { Obj = o, OrderID = o.OrderID ?? int.MaxValue }).OrderByDescending(o => o.OrderID).Select(o => o.Obj);

Upvotes: 0

Related Questions