使用Linq的两个列表的棘手组合

时间:2013-02-08 05:46:31

标签: c# .net linq lambda

我希望有人能够在这里指导我正确的方向......

public class SubmissionLog
{  
    public int PKId {get;set;}  
    public int SubmissionId {get;set;}  
    public DateTime Created {get;set;}   
    public int StatusId {get;set;}
}

这是数据:

1, 123, '1/24/2013 01:00:00', 1  
2, 456, '1/24/2013 01:30:00', 1  
3, 123, '1/25/2013 21:00:00', 2  
4, 456, '1/25/2013 21:30:00', 2  
5, 123, '2/25/2013 22:00:00', 1  
6, 123, '2/26/2013 21:00:00', 2  
7, 123, '2/16/2013 21:30:00', 1 

我想要的是: 我想知道某一天从StatusId 1到StatusId 2的平均时间跨度。

所以,让我们说日期是2013年2月26日,那么如果我第一次得到这样的列表,那么我认为会有意义:

var endlingList = (from sl in db.SubmissionLogs  
    where (DateTime.Now.AddDays(days).Date == sl.Created.Date) // days = passed number of days to make it 2/26/2013  
    && (sl.StatusId == 2)  
    select sl).ToList();

var endingLookup = endlingList.ToLookup(a => a.SubmissionId, a => a.Created); // thought of using lookup because Dictionary doesn't allow duplicates

之后我想我会找出起点

var startingList = (from sl in db.SubmissionLogs  
where endingList.Select(a => a.SubmissionId).ToArray().Contains(sl.QuoteId)  
&& sl.StatusId == 1
select sl).ToList();

然后我所做的就是:

var revisedList = endingLookup.Select(a =>
new SubmissionInterval {
    SubmissionId = a.Key,
    EndDateTime = endingLookup[a.Key].FirstOrDefault(), //This is where the problem is. This will only grab the first occurance.
    StartDateTime = startLookup[a.Key].FirstOrDefault() //This is where the problem is. This will only grab the first occurance.
});

然后我要做的是获得平均值(再次,这将仅包括状态1的初始或第一次发生以及某些提交ID提交日志的状态2):

return revisedList.Count() > 0 ? revisedList.Select(a=> a.EndDateTime.Subtract(a.StartDateTime).TotalHours).Average() : 0;

所以,我希望有人会先了解我的问题是什么......重新上限,我希望在每个状态1和2之间获得时间间隔。我将日期传入,然后我必须看看因为这确保了我会找到1的。如果我走了另一条路并寻找1,那么2可能不存在(不管怎样都不想这样)。

最后我想平均一些东西...... 所以让我们说如果一些提交在5h的时间跨度内首先从1变为2(我离开的代码,会让我达到这一点),那么让我们说它被重新分配到1然后它又回到了2新的时间跨度为6h,我希望能够得到两者并做到平均值,所以(5 + 6)/ 2。

由于

1 个答案:

答案 0 :(得分:1)

我想我明白你要做什么。这有帮助吗

void Main()
{
    var list = new List<SubmissionLog>
    {
        new SubmissionLog(1, 123, "1/24/2013 01:00:00", 1),
        new SubmissionLog(2, 456, "1/24/2013 01:30:00", 1),
        new SubmissionLog(3, 123, "1/25/2013 21:00:00", 2),
        new SubmissionLog(4, 456, "1/25/2013 21:30:00", 2),
        new SubmissionLog(5, 123, "2/25/2013 22:00:00", 1),
        new SubmissionLog(6, 123, "2/26/2013 21:00:00", 2),
        new SubmissionLog(7, 123, "2/16/2013 21:30:00", 1),
    };

    // split out status 1 and 2
    var s1s = list.Where (l => l.StatusId == 1).OrderBy (l => l.Created);
    var s2s = list.Where (l => l.StatusId == 2).OrderBy (l => l.Created);

    // use a sub-query to get the first s2 after each s1
    var q = s1s.Select (s1 => new 
        {
            s1, 
            s2 = s2s.FirstOrDefault (s2 => 
                s1.SubmissionId == s2.SubmissionId &&
                s2.Created >= s1.Created    
            )
        }
    ).Where (s => s.s1.PKId < s.s2.PKId && s.s2 != null);

        // extract the info we need 
        // note that TotalSecond is ok in Linq to Object but you'll 
        // probably need to use SqlFunctions or equivalent if this is to 
        // run against a DB.
    var q1 = q.Select (x => new 
        {
            Start=x.s1.Created,
            End=x.s2.Created,
            SubmissionId=x.s1.SubmissionId, 
            Seconds=(x.s2.Created - x.s1.Created).TotalSeconds
        }
    );

        // group by submissionId and average the time
    var q2 = q1.GroupBy (x => x.SubmissionId).Select (x => new {
        x.Key, 
        Count=x.Count (),
        Start=x.Min (y => y.Start),
        End=x.Max (y => y.End),
        Average=x.Average (y => y.Seconds)});
}

public class SubmissionLog
{  
    public SubmissionLog(int id, int submissionId, string date, int statusId)
    {
        PKId = id;
        SubmissionId = submissionId;
        Created = DateTime.Parse(date, CultureInfo.CreateSpecificCulture("en-US"));
        StatusId = statusId;
    }
    public int PKId {get;set;}  
    public int SubmissionId {get;set;}  
    public DateTime Created {get;set;}   
    public int StatusId {get;set;}
}