C# 在C中,合并数组中的项的最优雅方式是什么;单个较大的项目;?
我有一个C#应用程序,我从一个外部跟踪系统中提取数据,跟踪人们的请求,并将其存储在我的数据库中。比如说:C# 在C中,合并数组中的项的最优雅方式是什么;单个较大的项目;?,c#,collections,merge,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(); publ
public class Request
{
public DateTime Start {get;set;}
public DateTime End {get;set;}
public int PersonId {get;set;}
}
IEnumerable<Request> requests = GetExternalRequests();
public class Request
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
public int PersonId { get; set; }
public Request(DateTime start)
{
while (!IsWorkingDay(start))
start = start.AddDays(1);
Start = start;
End = start.AddDays(1);
while (!IsWorkingDay(End))
End = End.AddDays(1);
}
private bool IsWorkingDay(DateTime date)
{
return date.DayOfWeek != DayOfWeek.Saturday && date.DayOfWeek != DayOfWeek.Sunday;
}
public bool Intersects(Request otherRequest)
{
if (otherRequest == this)
return true;
return !(otherRequest.End < Start || otherRequest.Start > End);
}
public void Merge(Request otherRequest)
{
if (otherRequest.Start < Start)
Start = otherRequest.Start;
if (otherRequest.End > End)
End = otherRequest.End;
}
}
公共类请求
{
公共日期时间开始{get;set;}
公共日期时间结束{get;set;}
公共int PersonId{get;set;}
}
IEnumerable 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.
}
}
}
IEnumerable requests=GetExternalRequests();
IEnumerable previousRequests=GetAllPreviousRequests();
Dictionary cachedDictionary=CacheAllRequestsByDate和PersonId(请求,以前的请求)
var groupedByPerson=requests.GroupBy(r=>r.PersonId);
foreach(groupedByPerson中的var组)
{
foreach(请求位于group.OrderBy(r=>r.StartDate)中)
{
var偏移=1;
if(request.StartDate.DayOfWeek==DayOfWeek.Friday)
{
偏移量=3;
}
if(cachedDictionary.ContainsKey(request.PersonId+request.StartDate.AddDays(offset))
{
//从列表中删除请求,并将下一个请求的开始日期更改为此请求的开始日期。
}
}
}
所以我想得到一些建议,看看是否有更优雅的方式来“合并”这些结果
增加一些清晰度(基于下面的一些评论)
- 请求不能重叠(请考虑假期请求)
- 如果我周一已经有一个以前的请求,而周二又有一个新的请求,那么我也想合并这些请求
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);
}
private静态IEnumerable GetExternalRequests()
{
生成返回新请求(新日期时间(2015,1,4),新日期时间(2015,1,4),1);
生成返回新请求(新日期时间(2015,1,5),新日期时间(2015,1,5),1);
生成返回新请求(新日期时间(2015,1,6),新日期时间(2015,1,6),1);
生成返回新请求(新日期时间(2015,1,7),新日期时间(2015,1,7),1);
生成返回新请求(新日期时间(2015,1,8),新日期时间(2015,1,8),1);
生成返回新请求(新日期时间(2015,1,11),新日期时间(2015,1,11),1);
生成返回新请求(新日期时间(2015,1,15),新日期时间(2015,1,15),1);
生成返回新请求(新日期时间(2015,1,19),新日期时间(2015,1,19),1);
生成返回新请求(新日期时间(2015,1,26),新日期时间(2015,1,26),1);
生成返回新请求(新日期时间(2015,1,4),新日期时间(2015,1,4),2);
生成返回新请求(新日期时间(2015,1,7),新日期时间(2015,1,7),2);
}
然后,您可以使用GroupBy合并数据,然后聚合以合并连续的天数
请参阅下面的代码:
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();
}
私有静态IList合并请求(IEnumerable请求)
{
return requests.GroupBy(r=>r.PersonId)
.Aggregate(新堆栈(),(列表,分组)=>
{
foreach(grouping.OrderBy(r=>r.StartDate)中的var请求)
{
var peek=list.Any()?list.peek():null;
if(peek?.EndDate.Date.Day+1==request.StartDate.Date.Day)
peek.EndDate=request.EndDate;
其他的
列表、推送(请求);
}
退货清单;
})
.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}");
}
publicstaticvoidmain(字符串[]args)
{
Thread.CurrentThread.CurrentCulture=CultureInfo.GetCultureInfo(“en-US”);
IEnumerable requests=GetExternalRequests();
var requestsMerge=合并请求(请求);
foreach(requestsMerge中的var请求)
WriteLine($“个人Id:{request.PersonId}-StartDate:{request.StartDate}-EndDate:{request.EndDate}”);
}
输出数据如下:
人员Id:1-开始日期:2015年4月1日12:00:00-结束日期:2015年8月1日12:00:00
人员Id:1-开始日期:2015年11月1日12:00:00-结束日期:2015年12月1日12:00:00
人员Id:1-开始日期:2015年1月19日12:00:00-结束日期:2015年1月19日12:00:00
个人Id:1-开始日期:2015年1月26日12:00:00-结束日期:2015年1月26日12:00:00
人员Id:2-开始日期:2015年1月4日12:00:00-结束日期:2015年1月4日12:00:00
人员Id:2-开始日期:2015年7月1日12:00:00-结束日期:2015年7月1日12:00:00
cachedDictionary.Contains
在字典上
是一种linq方法,它使用蛮力搜索。这肯定是算法中最慢的部分
我建议更改内部循环的内容。不要尝试修改请求。相反,请创建一个新的请求列表,仅当内部循环中遇到非连续的一天时才创建一个新请求。请求的结束将在下一个请求启动或循环完成时设置。您可以尝试som就像这样:
public class Request
{
public DateTime Start {get;set;}
public DateTime End {get;set;}
public int PersonId {get;set;}
}
IEnumerable<Request> requests = GetExternalRequests();
public class Request
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
public int PersonId { get; set; }
public Request(DateTime start)
{
while (!IsWorkingDay(start))
start = start.AddDays(1);
Start = start;
End = start.AddDays(1);
while (!IsWorkingDay(End))
End = End.AddDays(1);
}
private bool IsWorkingDay(DateTime date)
{
return date.DayOfWeek != DayOfWeek.Saturday && date.DayOfWeek != DayOfWeek.Sunday;
}
public bool Intersects(Request otherRequest)
{
if (otherRequest == this)
return true;
return !(otherRequest.End < Start || otherRequest.Start > End);
}
public void Merge(Request otherRequest)
{
if (otherRequest.Start < Start)
Start = otherRequest.Start;
if (otherRequest.End > End)
End = otherRequest.End;
}
}
公共类请求
{
公共日期时间开始{get;set;}
公共日期时间结束{get;set;}
公共int PersonId{get;set;}