开发者

Linq self-join and filter

I have a List<ClaimEvent> made up of this class:

public class ClaimEvent
{
    public ClaimEventType ClaimEventClaimEventType { get; set; }
    public DateTime OccurredOn { get; set; }
    public DateTime Created { get; set; }
    public DateTime Modified { get; set; }
    public string CreatedBy { get; set; }
    public string ModifiedBy { get; set; }
}

'ClaimEventType' is like so...

public class ClaimEventType
{
    public ClaimEventType()
    {
        Cancels = new List<ClaimEventType>();
        CancelledBy = new List<ClaimEventType>();
    }

    public int ClaimEventTypeId { get; set; }
    public string ClaimEventTypeName { get; set; }
    public List<ClaimEventType> Cancels { get; set; }
    public List<ClaimEventType> Ca开发者_开发问答ncelledBy { get; set; }
}

Cancels lists all event types that this event cancels when it appears after them in the list ordered by OccurredOn. CancelledBy is the inverse, that is, the event is cancelled if one of the CancelledBy events appears after it.

How can I query a list of these objects so that items that are cancelled by other items in the list do not appear in the results?


Pretty straightforward, though you seem to be duplicating effort listing both cancels and cancelled by:

List<ClaimEvent> theList = new List<ClaimEvent>();

theList.RemoveAll(i => (from j in theList
                        where j.ClaimEventClaimEventType.Cancels.Contains(i.ClaimEventClaimEventType) &&
                        j.OccurredOn > i.OccurredOn
                        select j).Count() > 0);

Remove all elements from the collection object where there exists another ClaimEvent in the collection that cancels a ClaimEvent of this element's type and occurred after this claim event (i.e. where there are one or more such elements).

EDIT: Functionally equivalent code with more readable syntax

This may also be accomplished using a second delegate method in a call to Exists to find any cancelling events:

theList.RemoveAll(i =>
    theList.Exists(j =>
        j.ClaimEventClaimEventType.Cancels.Contains(i.ClaimEventClaimEventType) &&
        j.OccurredOn > i.OccurredOn));

Resources

MSDN: List(Of T).RemoveAll Method


If I understand your requirement correctly, I think you might want to go for something like this. It essentially iterates over the sequence and builds a HashSet of event types already present. For each ClaimEvent in the sequence, it checks the previously existing event types for one of the current object's cancelling types. If it doesn't find one, it can yield the current object and add its type to the set.

public static IEnumerable<ClaimEvent> GetUncancelledEvents(this IEnumerable<ClaimEvent> source)
{   
    // note: override Equals & GetHashCode in ClaimEventType**
    HashSet<ClaimEventType> existingEventTypes = new HashSet<ClaimEventType>();

    foreach (var @event in source)
    {
        bool isCancelled = false;
        foreach (var cancellingEvent in @event.ClaimEventClaimEventType.CancelledBy)
        {
            if (existingEventTypes.Contains(cancellingEvent))
            {
                isCancelled = true;
                break;
            }
        }

        if (!isCancelled)
        {
            existingEventTypes.Add(@event.ClaimEventClaimEventType);
            yield return @event;
        }
    }
}

...

var uncancelledEvents = eventsList.GetUncancelledEvents();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜