Matt Foxx Duncan
Matt Foxx Duncan

Reputation: 2094

Adding items to a list based on a reference to parent item

I have two List of the same type Parcel.

public class Parcel
{
 int Id {get;set;}
 int RecipientID {get;set;}
 DateTime CreatedOn {get;set;}
}

List<Parcel> aparcels = postFacade.GetParcels()
                               .OrderByDescending(x => x.CreatedOn);

List<Parcel> bparcels = postFacade.GetReplyParcels();

The Parcel objects from aparcels are top-level items. Their RecipientID is never another Parcel Id.

The Parcel objects from bparcels are replies to Parcel objects in aparcel. Their RecipientID is always a Parcel Id. However bparcels contains objects all replying Parcel objects, not just for the list of Parcel objects in aparcel.

I want to create a new list of Parcel objects from aparcels sorted by CreatedOn.

However if a Parcel from aparcels is referenced by a Parcel from bparcels(via RecipientID) I want to add the corresponding Parcel from bparcels after the Parcel from aparcel in the list.

I then want to check bparcels for any other Parcel objects that reference the "replying" Parcel and add it to the list, checking bparcels recursively until no more "reply" Parcel objects are found.

This is what I've come up with:

        List<Parcel> parcels = new List<Parcels>();
        var replies = bposts.ToDictionary(u => u.RecipientID, p => p.Id);
        foreach (var p in aparcels)
        {
            parcels.Add(p);
            int commid = p.Id;
            int val;
            while (replies.TryGetValue(commid, out val))
            {
                parcels.Add(parcelFacade.GetById(val));
                commid = val;
            }
        }

Is there any way I can increase the performance of this operation? It will potentially be dealing with hundreds/thousands of Parcel objects.

Upvotes: 2

Views: 568

Answers (2)

AlexDev
AlexDev

Reputation: 4717

I think you should store a reference to the Parcels themselves in the dictionary, which are already in the list so you don't have to load them again from you Facade, which is probably what is slowing down your code.

    List<Parcel> parcels = new List<Parcels>();
    var replies = bposts.ToDictionary(u => u.RecipientID);
    foreach (var p in aparcels)
    {
        parcels.Add(p);
        Parcel parent = p;

        while (replies.TryGetValue(parent.Id, out parent))
        {
            parcels.Add(parent);
        }
    }

Or, to make it even shorter:

    foreach (var p in aparcels)
    {
        var current = p;
        do parcels.Add(current);
        while (replies.TryGetValue(current.Id, out current));
    }

Upvotes: 1

Bill Hatter
Bill Hatter

Reputation: 165

I think you're overcomplicating things a bit.

You can do a simple loop through the original posts collection, and add in what you need easily by using:

foreach(var a in aposts.OrderByDescending(p => p.CreatedOn))
{
    parcels.Add(a);
    parcels.Add(bposts.Where(b => a.ID == b.RecipientID).OrderByDescending(p => p.CreatedOn));
}

UPDATE

Taking into account the fact that you want to loop through each bpost reply to get any other replies to it, I've written an iteration method that will loop until all parent -> children -> grandchildren -> etc. are resolved. This should get everything you want based upon created on field.

foreach(var a in aposts.OrderByDescending(p => p.CreatedOn))
{
    parcels.Add(a);
    foreach(var b in bposts.Where(bpost => bpost.RecipientID == a.ID).OrderByDescending(bpost => bpost.CreatedOn))
    {
        parcels.AddRange(Iterate(b, bposts));
    }
}

public IList<Parcel> Iterate(Parcel a, IList<Parcel> b)
{
    var parcels = new List<Parcel>();
    foreach(var post in b.Where(bpost => a.ID == bpost.RecipientID).OrderByDescending(bpost => bpost.CreatedOn))
    {
        parcels.Add(post);
        parcels.AddRange(Iterate(post, b));
    }
    return parcels;
}

Upvotes: 0

Related Questions