比较2个列表之间的值并减去公共元素的值 - C#

时间:2017-11-04 08:06:36

标签: c# entity-framework list linq

我需要准备一张图表,其中我需要显示3行。一个用于显示一周的新问题,一个用于一周的已结束问题,第三个用于一周的总公开问题。出于这个原因,我准备了一个查询,并且能够成功创建2个单独的列表 - 一个列表维护每周新发布的计数,第二个列表维护每周的已结算问题计数。

以下是第一个列表的示例数据(维护新问题的列表):

    [0]: { Week = {6/14/2015 12:00:00 AM}, Count = 1 }
    [1]: { Week = {3/5/2017 12:00:00 AM}, Count = 1 }
    [2]: { Week = {5/21/2017 12:00:00 AM}, Count = 4 }
    [3]: { Week = {6/4/2017 12:00:00 AM}, Count = 7 }
    [4]: { Week = {6/11/2017 12:00:00 AM}, Count = 4 }
    [5]: { Week = {6/25/2017 12:00:00 AM}, Count = 7 }
    [6]: { Week = {7/9/2017 12:00:00 AM}, Count = 3 }

根据以上数据,我得到了特定周的未决问题总数。

注意:对于这两个列表,周值包含星期日的日期。因为我需要从星期一开始的一周,同时在图表中显示数据。

类似地,对于第二个列表的样本数据(一个维持已关闭的问题):

[0]: { Week = {12/13/2015 12:00:00 AM}, Count = 1 }
[1]: { Week = {7/9/2017 12:00:00 AM}, Count = 3 }
[2]: { Week = {6/18/2017 12:00:00 AM}, Count = 2 }
[3]: { Week = {7/23/2017 12:00:00 AM}, Count = 8 }
[4]: { Week = {10/1/2017 12:00:00 AM}, Count = 6 }
[5]: { Week = {8/6/2017 12:00:00 AM}, Count = 3 }
[6]: { Week = {9/17/2017 12:00:00 AM}, Count = 5 }

根据以上数据,我得到了特定周的已结算问题的总数。

以下是这些列表的代码:

var openIssuesList = getDetails.Where(x => x.ChangedTo == "Open").Select(x => new { Week = x.Date.AddDays(x.Date.DayOfWeek == DayOfWeek.Sunday ? 0 : 7 - (int)x.Date.DayOfWeek).Date, Detail = x }).GroupBy(x => x.Week).Select(x => new { Week = x.Key, Count = x.Count() }).ToList();


var closedIssuesList = getDetails.Where(x => x.ChangedTo == "Closed").Select(x => new { Week = x.Date.AddDays(x.Date.DayOfWeek == DayOfWeek.Sunday ? 0 : 7 - (int)x.Date.DayOfWeek).Date, Detail = x }).GroupBy(x => x.Week).Select(x => new { Week = x.Key, Count = x.Count() }).ToList();

现在剩下的最后一块是使用这两个列表中的值来创建一个新列表,这两个列表应包含一周内总开放问题的数据。

说明:

  1. 我需要比较以上2个列表中的周值。
  2. 如果周值相等,则计算它们之间的差值 两个列表中特定周的计数值。
  3. 在此新列表中保存周值和计算值(计算差异后)。
  4. 如果周值不匹配,则选择这些值(周和 计数)并按原样存储在这个新列表中。
  5. 所以从上面提供的示例数据中可以看出新列表应该如何:

    [0]: { Week = {6/14/2015 12:00:00 AM}, Count = 1 }    // As is value from first list - openIssuesList
    [1]: { Week = {12/13/2015 12:00:00 AM}, Count = 1 }  // As is value from second list - closedIssuesList
    [2]: { Week = {3/5/2017 12:00:00 AM}, Count = 1 }  // As is value from first list - openIssuesList
    [3]: { Week = {5/21/2017 12:00:00 AM}, Count = 4 }  // As is value from first list - openIssuesList
    [4]: { Week = {6/4/2017 12:00:00 AM}, Count = 7 }  // As is value from first list - openIssuesList
    [5]: { Week = {6/11/2017 12:00:00 AM}, Count = 4 }  // As is value from first list - openIssuesList
    [6]: { Week = {6/18/2017 12:00:00 AM}, Count = 2 }  // As is value from second list - closedIssuesList
    [7]: { Week = {6/25/2017 12:00:00 AM}, Count = 7 }   // As is value from first list - openIssuesList
    [8]: { Week = {7/9/2017 12:00:00 AM}, Count = 0 }   // These is common week from both lists. Hence we calculate the difference between count values. So 3-3 = 0.
    [9]: { Week = {7/23/2017 12:00:00 AM}, Count = 8 }  // As is value from second list - closedIssuesList
    [10]: { Week = {8/6/2017 12:00:00 AM}, Count = 3 }   // As is value from second list - closedIssuesList
    [11]: { Week = {9/17/2017 12:00:00 AM}, Count = 5 }    // As is value from second list - closedIssuesList
    [12]: { Week = {10/1/2017 12:00:00 AM}, Count = 6 }    // As is value from second list - closedIssuesList
    

    从上面的数据中可以看到此列表的第8个元素。这个列表中的一周7/9/2017在openIssuesList(第6个元素)和closedIssuesList(第2个元素)中很常见

    实现此列表的代码是什么?

    注意:我已从这些列表中的所有DateTime值中删除代码中的Time元素值。因此,所有日期值都显示在这些列表中的12:00:00 AM。

2 个答案:

答案 0 :(得分:1)

如果您不需要LINQ解决方案,则可以创建帮助程序类

public class WeekCount
{
    public DateTime Week { get; set; }
    public int Count { get; set; }
}

,使用此类修改您的选择

.Select(x => new WeekCount { Week = x.Key, Count = x.Count() })

,然后简单地做:

var totalIssuesList = openIssuesList.ToList();

foreach (var closedWeekCount in closedIssuesList)
{
    var totalWeekCount = totalIssuesList.FirstOrDefault(owc => owc.Week == closedWeekCount.Week);
    if (totalWeekCount != null)
    {
        totalWeekCount.Count = totalWeekCount.Count - closedWeekCount.Count;
    }
    else
    {
        totalIssuesList.Add(closedWeekCount);
    }
}

totalIssuesList = totalIssuesList.OrderBy(twc => twc.Week).ToList();

答案 1 :(得分:1)

要使用LINQ执行此操作,您可以考虑这两个列表的完全外连接。

助手类:

    public class IssueCount
    {
        public DateTime Week { get; set; }
        public int Count { get; set; }
    }

然后

        // Union left outer join and right outer join to perform full outer join
        // https://stackoverflow.com/a/5491381/5682608
        var leftOuterJoin = from newIssue in newIssues
                            join closedIssue in closedIssues
                            on newIssue.Week equals closedIssue.Week
                            into temp
                            from closedIssue in temp.DefaultIfEmpty(new IssueCount { Week = newIssue.Week, Count = 0 })
                            select new IssueCount
                            {
                                Week = newIssue.Week,
                                Count = newIssue.Count - closedIssue.Count
                            };

        var rightOuterJoin = closedIssues.Where(issue => !newIssues.Select(newIssue => newIssue.Week).Contains(issue.Week));

        // Modified: Following code can generate duplicated entries when
        // 2 IssueCounts of the same Week have different values in Count property
        // 
        //var rightOuterJoin = from closedIssue in closedIssues
        //                     join newIssue in newIssues
        //                     on closedIssue.Week equals newIssue.Week
        //                     into temp
        //                     from newIssue in temp.DefaultIfEmpty(new IssueCount { Week = closedIssue.Week, Count = 0 })
        //                     select new IssueCount
        //                     {
        //                         Week = closedIssue.Week,
        //                         Count = closedIssue.Count - newIssue.Count
        //                     };

        var fullOuterJoin = leftOuterJoin.Union(rightOuterJoin);

        foreach (var issue in fullOuterJoin.OrderBy(i => i.Week))
        {
            Console.WriteLine($"{issue.Week.ToString("MM/dd/yyyy")} : {issue.Count}");
        }

这应输出

06/14/2015 : 1
12/13/2015 : 1
03/05/2017 : 1
05/21/2017 : 4
06/04/2017 : 7
06/11/2017 : 4
06/18/2017 : 2
06/25/2017 : 7
07/09/2017 : 0
07/23/2017 : 8
08/06/2017 : 3
09/17/2017 : 5
10/01/2017 : 6