Linq自我加入和过滤

时间:2011-06-02 20:56:47

标签: c# linq self-join

我有一个List<ClaimEvent>由这个班级组成:

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'就是这样......

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> CancelledBy { get; set; }
}

Cancels列出了此事件在OccurredOn排序的列表中显示在它们之后取消的所有事件类型。 CancelledBy是相反的,也就是说,如果CancelledBy个事件之一出现在其后,则会取消该事件。

如何查询这些对象的列表,以便列表中其他项目取消的项目不会出现在结果中?

2 个答案:

答案 0 :(得分:2)

非常直截了当,尽管你似乎正在重复列出取消和取消的努力:

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);

从集合中删除所有元素,其中集合中存在另一个ClaimEvent,该集合取消此元素类型的ClaimEvent并在此声明事件之后发生(即,存在一个或多个此类元素的地方)。

编辑:具有更多可读语法的功能相同的代码

这也可以通过调用Exists使用第二个委托方法来查找任何取消事件:

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

<强>资源

MSDN: List(Of T).RemoveAll Method

答案 1 :(得分:1)

如果我理解你的要求,我想你可能会想要这样的事情。它基本上遍历序列并构建已存在的HashSet个事件类型。对于序列中的每个ClaimEvent,它会检查先前存在的事件类型,以查找当前对象的一个​​取消类型。如果找不到,则可以生成当前对象并将其类型添加到集合中。

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();