比较2个列表之间的值并减去常见元素的值 – C#

我需要准备一张图表,其中我需要显示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. 如果周值不匹配,则选择这些值(Week和Count)并将它们按原样存储在此新列表中。

所以从上面提供的示例数据中可以看出新列表应该如何:

 [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。

如果您不是绝对需要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(); 

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

助手class:

  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