c# - 在 C# 中,将数组中的项合并为 "single larger item"的一部分的最优雅方法是什么?

标签 c# collections merge

我有一个 C# 应用程序,我正在从跟踪人们请求的外部跟踪系统中提取数据,并将它们存储在我的数据库中。所以像这样:

public class Request
{
   public DateTime Start {get;set;}
   public DateTime End {get;set;}
   public int PersonId {get;set;}
} 

IEnumerable<Request> requests = GetExternalRequests();

GetExternalRequests() 的细节与问题无关。

问题是该服务将事情分解为每一天向我发送一个请求(即使该请求是多天的请求)

例如,如果一个人提出一个整周(周一到周五)的请求,我在数组中得到 5 个不同的项目(每个都有一个日期),我想将它们“合并”成一个请求开始 = 星期一和结束 = 星期五,以避免将 5 条不同的记录保存到我的数据库中。

到目前为止,我觉得这是一个非常不优雅的解决方案,我循环遍历所有请求并将结果放入字典中,然后运行下面的代码

IEnumerable<Request> requests = GetExternalRequests();

IEnumerable<Request> previousRequests = GetAllPreviousRequests();

Dictionary<string, Request> cachedDictionary = CacheAllRequestsByDateandPersonId(requests, previousRequests)

var groupedByPerson = requests.GroupBy(r=>r.PersonId);
foreach (var group in groupedByPerson)
{
    foreach (Request request in group.OrderBy(r=>r.StartDate) 
    {
         var offSet = 1;
         if (request.StartDate.DayOfWeek == DayOfWeek.Friday)
         {
             offSet = 3;
         }
         if (cachedDictionary.ContainsKey(request.PersonId + request.StartDate.AddDays(offset))
         {
              //delete the request from the list and change the start date of the next request to the start date of this request.
         }
    }
}

所以我想得到一些建议,看看是否有更优雅的方式来“合并”这些结果。

增加一些清晰度(基于下面的一些评论)

  • 请求不能重叠(想想休假请求)
  • 如果我在周一已经收到了之前的请求,而在周二又收到了一个新请求,那么我也想合并这些请求

最佳答案

假设您的 GetExternalRequests 返回一些类似的种子数据

private static IEnumerable<Request> GetExternalRequests()
{
    yield return new Request(new DateTime(2015, 1, 4), new DateTime(2015, 1, 4), 1);
    yield return new Request(new DateTime(2015, 1, 5), new DateTime(2015, 1, 5), 1);
    yield return new Request(new DateTime(2015, 1, 6), new DateTime(2015, 1, 6), 1);
    yield return new Request(new DateTime(2015, 1, 7), new DateTime(2015, 1, 7), 1);
    yield return new Request(new DateTime(2015, 1, 8), new DateTime(2015, 1, 8), 1);

    yield return new Request(new DateTime(2015, 1, 11), new DateTime(2015, 1, 11), 1);
    yield return new Request(new DateTime(2015, 1, 15), new DateTime(2015, 1, 15), 1);

    yield return new Request(new DateTime(2015, 1, 19), new DateTime(2015, 1, 19), 1);

    yield return new Request(new DateTime(2015, 1, 26), new DateTime(2015, 1, 26), 1);

    yield return new Request(new DateTime(2015, 1, 4), new DateTime(2015, 1, 4), 2);
    yield return new Request(new DateTime(2015, 1, 7), new DateTime(2015, 1, 7), 2);
}

然后你可以使用GroupBy合并你的数据,然后Aggregate合并连续的天数

请看下面的代码:

private static IList<Request> MergeRequests(IEnumerable<Request> requests)
{
    return requests.GroupBy(r => r.PersonId)
                    .Aggregate(new Stack<Request>(), (list, grouping) =>
                    {
                        foreach (var request in grouping.OrderBy(r => r.StartDate))
                        {
                            var peek = list.Any() ? list.Peek() : null;
                            if (peek?.EndDate.Date.Day + 1 == request.StartDate.Date.Day)
                                peek.EndDate = request.EndDate;
                            else
                                list.Push(request);
                        }
                        return list;
                    })
                    .OrderBy(x => x.PersonId).ThenBy(x => x.StartDate)
                    .ToList();
}

那么让我们测试一下这个解决方案

public static void Main(string[] args)
{
    Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-US");
    IEnumerable<Request> requests = GetExternalRequests();

    var requestsMerge = MergeRequests(requests);


    foreach (var request in requestsMerge)
        Console.WriteLine($"Person Id: {request.PersonId} - StartDate: {request.StartDate} - EndDate: {request.EndDate}");
}

输出数据是:

Person Id: 1 - StartDate: 1/4/2015 12:00:00 AM - EndDate: 1/8/2015 12:00:00 AM

Person Id: 1 - StartDate: 1/11/2015 12:00:00 AM - EndDate: 1/12/2015 12:00:00 AM

Person Id: 1 - StartDate: 1/19/2015 12:00:00 AM - EndDate: 1/19/2015 12:00:00 AM

Person Id: 1 - StartDate: 1/26/2015 12:00:00 AM - EndDate: 1/26/2015 12:00:00 AM

Person Id: 2 - StartDate: 1/4/2015 12:00:00 AM - EndDate: 1/4/2015 12:00:00 AM

Person Id: 2 - StartDate: 1/7/2015 12:00:00 AM - EndDate: 1/7/2015 12:00:00 AM

关于c# - 在 C# 中,将数组中的项合并为 "single larger item"的一部分的最优雅方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34601819/

相关文章:

java - Spring /json : Convert a typed collection like List<MyPojo>

excel - 关于如何在第二列中的两个值之间组合单元格的更好的解决方案

c# - 从 BitArray 转换为字节

c# - Entity Framework : How to insert data from a list which does not already exists in DB table

java - SortedMultiset 返回对象集合(不仅仅是对象计数)?

C# : How to compare two collections (System. Collection.Generic.List<T>) 使用 Linq/Lambda?

c# - 将 C# 库移植到 Windows Phone 8?

c# - Sprache 解析器和字符转义

algorithm - K-way归并排序在多台主机上划分

C# - DataTable.Merge() 是否添加重复项或更新?