[英]Consolidating objects by DateTime values in C#
I have a list of objects in C# with "BeginDate" and "EndDate" DateTime properties. 我在C#中具有“ BeginDate”和“ EndDate” DateTime属性的对象列表。 I need to create a new list of these objects with all the objects consolidated when the BeginDate of one object matches the EndDate of the previous one within 24 hours, going back until there is a break longer than 24 hours.
当一个对象的BeginDate与24小时内的上一个EndDate匹配时,我需要创建一个包含所有对象的所有对象的新列表,直到间隔超过24小时为止。
For example. 例如。 I have a list like so
我有一个像这样的清单
BeginDate EndDate
Object 1 12/21/2017 01/20/2018
Object 2 12/01/2017 12/21/2017
Object 3 10/25/2017 12/01/2017
Object 4 09/17/2017 10/25/2017
Object 5 08/01/2017 09/02/2017
Object 6 06/25/2017 07/26/2017
Object 7 04/20/2017 06/25/2017
that needs to be turned into a list like this 需要变成这样的列表
BeginDate EndDate
Object 1 09/17/2017 01/20/2018
Object 2 08/01/2017 09/02/2017
Object 3 4/20/2017 07/26/2017
My issue is further exacerbated by the fact that if the Object represents an ongoing project, then the EndDate might be a null value. 如果对象表示正在进行的项目,那么EndDate可能为空值,这进一步加剧了我的问题。 So the original developers chose to use a DateTime?
因此,原始开发人员选择使用DateTime吗? type instead of a regular DateTime value for that field.
类型,而不是该字段的常规DateTime值。 So you could have a situation where you have
所以你可能会遇到这样的情况
BeginDate EndDate
Object 1 12/21/2017 null
Object 2 12/01/2017 12/21/2017
which would have to be converted to either 必须将其转换为
BeginDate EndDate
Object 1 12/01/2017 null
or 要么
BeginDate EndDate
Object 1 12/01/2017 (DateTime.Now)
Right now, I'm trying this but it's not completely consolidating all the objects: 现在,我正在尝试这样做,但是它并没有完全合并所有对象:
for (var index = 0; index < ProjectList.Count; index++)
{
Project_BL ThisProject = ProjectList[index];
Project_BL nextProject = ProjectList[index + 1];
if (index + 1 < ProjectList.Count && ProjectList[index+1] != null)
{
DateTime TempEndDate = nextProject.EndDate ?? DateTime.Now;
TimeSpan DifferenceBetweenProjectsTimespan =
ThisProject.BeginDate.Subtract(TempEndDate);
int DifferenceBetweenProjects = (int)DifferenceBetweenProjectsTimespan.TotalHours;
if (DifferenceBetweenProjects <= 24)
{
if (IsLongProject == true)
{
nextProject.ProjectNature = "Long-term";
}
nextProject.EndDate = ThisProject.EndDate;
ProjectList.RemoveAt(index);
continue;
}
else
{
ProjectList.Add(ThisProject);
index++;
continue;
}
}
else
{
ProjectList.Add(ThisProject);
}
}
return ProjectList;
Anyone have any ideas? 有人有想法么? I'm banging my head against the wall at this point.
我现在把头撞在墙上。 So any help would be appreciated.
因此,任何帮助将不胜感激。
Here is my solution (DotNetFiddle Example) 这是我的解决方案(DotNetFiddle示例)
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var projectList = new List<Project>
{
new Project{Name = "Object 1", BeginDate = new DateTime(2017,12,21), EndDate = new DateTime(2018,01,20)},
new Project{Name = "Object 2", BeginDate = new DateTime(2017,12,01), EndDate = new DateTime(2017,12,21)},
new Project{Name = "Object 3", BeginDate = new DateTime(2017,10,25), EndDate = new DateTime(2017,12,01)},
new Project{Name = "Object 4", BeginDate = new DateTime(2017,09,17), EndDate = new DateTime(2017,10,25)},
new Project{Name = "Object 5", BeginDate = new DateTime(2017,08,01), EndDate = new DateTime(2017,09,02)},
new Project{Name = "Object 6", BeginDate = new DateTime(2017,06,25), EndDate = new DateTime(2017,07,26)},
new Project{Name = "Object 7", BeginDate = new DateTime(2017,04,20), EndDate = new DateTime(2017,06,25)},
};
var newList = new List<Project>();
while(projectList.Count > 0)
{
var item = projectList.ElementAt(0);
projectList.Remove(item);
newList.Add(item);
//Console.WriteLine(item);
var match = Match(item, projectList);
while (match != null)
{
//Console.WriteLine("match: " + match.ToString());
projectList.Remove(match);
item.BeginDate = item.BeginDate < match.BeginDate ? item.BeginDate : match.BeginDate;
item.EndDate = item.EndDate > match.EndDate ? item.EndDate : match.EndDate;
item.IsLongTerm = true;
//Console.WriteLine("adjusted: " + item.ToString());
match = Match(item, projectList);
}
}
foreach(var project in newList)
{
Console.WriteLine(project.ToString());
}
}
private static Project Match(Project project, IEnumerable<Project> projects)
{
var result = projects.FirstOrDefault(p =>
(project.BeginDate.AddDays(-1) < p.BeginDate && p.BeginDate < project.EndDate.AddDays(1) )
|| (project.BeginDate.AddDays(-1) < p.EndDate && p.EndDate < project.EndDate.AddDays(1)) );
return result;
}
}
public class Project
{
public string Name { get; set; }
public DateTime BeginDate { get; set; }
public DateTime EndDate { get; set; }
public bool IsLongTerm { get; set; }
public override string ToString()
{
return Name + " " + BeginDate.ToString("yyyy-MM-dd") + " " + EndDate.ToString("yyyy-MM-dd");
}
}
Result: 结果:
Object 1 2017-09-17 2018-01-20
对象1 2017-09-17 2018-01-20
Object 5 2017-08-01 2017-09-02
对象5 2017-08-01 2017-09-02
Object 6 2017-04-20 2017-07-26
对象6 2017-04-20 2017-07-26
Here is my attempt using simplified enumeration 这是我尝试使用简化的枚举
IEnumerable<Project> Consolidate(IEnumerable<Project> data) {
// I need to create a new list of these objects with all the objects
//consolidated when the BeginDate of one object matches the EndDate
//of the previous one within 24 hours, going back until there is a break longer than 24 hours.
using (var e = data.GetEnumerator()) {
if (e.MoveNext()) {
var previous = e.Current;
while (e.MoveNext()) {
var next = e.Current;
if (previous.BeginDate.AddDays(-1) > next.EndDate) {
yield return previous;
previous = next;
continue;
}
previous = new Project {
BeginDate = next.BeginDate,
EndDate = previous.EndDate ?? DateTime.Now
};
}
yield return previous;
}
}
}
Which produces the desired result for the above stated cases including null
end dates. 对于上述情况(包括
null
结束日期),这将产生期望的结果。
There is room to generalize this into an extension method if so desired. 如果需要,可以将其概括为扩展方法。 You would just need to provide a predicate for the condition and a
Func
for the building of the consolidated object. 您只需要提供条件谓词和构建合并对象的
Func
。
Here you go find my example here 在这里,您可以在这里找到我的示例
public class Project
{
public Project(string name, DateTime beginDate) : this(name, beginDate, null) { }
public Project(string name, DateTime beginDate, DateTime? endDate)
{
Name = name;
BeginDate = beginDate;
EndDate = endDate;
}
public string Name { get; set; }
public DateTime BeginDate { get; set; }
public DateTime? EndDate { get; set; }
public override string ToString()
{
return $"{Name}:\t{BeginDate.ToShortDateString()}\t:\t{(EndDate.HasValue ? EndDate.Value.ToShortDateString() : "Present")}";
}
}
private static List<Project> Consolidate(List<Project> projects)
{
var result = new List<Project>();
// if empty return
if (!projects.Any()) return result;
// adding first project to a new list
// and removing it from the main list
result.Add(projects.First());
projects.Remove(projects.First());
// loop over all projects in the main list
projects.ForEach(p =>
{
var endDate = p.EndDate.HasValue ? p.EndDate.Value : DateTime.Today;
// checking if any of the projects in the new list
// starts within 24 hours of the end date of the
// current project
if (result.Any(r => r.BeginDate >= endDate && r.BeginDate.Subtract(endDate) <= TimeSpan.FromDays(1) && r.Name != p.Name))
{
// if you find any get it
var match = result.First(r => r.BeginDate >= endDate && r.BeginDate.Subtract(endDate) <= TimeSpan.FromDays(1) && r.Name != p.Name);
var index = result.IndexOf(match);
// create new project that consalidate both projects
result[index] = new Project(match.Name, p.BeginDate, match.EndDate);
}
else
{
// if didn't find any add the current
// project to the new list
result.Add(p);
}
});
return result;
}
P6: 4/20/2017 : 7/26/2017
P5: 8/1/2017 : 9/2/2017
P1: 9/17/2017 : 1/20/2018
P6: 4/20/2017 : Present
P5: 8/1/2017 : 9/2/2017
P4: 9/17/2017 : Present
P1: 10/25/2017 : 1/20/2018
Here is my approach... 这是我的方法...
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var projectList = new List<Project>
{
new Project{Id = "Object 0", BeginDate = new DateTime(2018,01,20), EndDate = null},
new Project{Id = "Object 1", BeginDate = new DateTime(2017,12,21), EndDate = new DateTime(2018,01,20)},
new Project{Id = "Object 2", BeginDate = new DateTime(2017,12,01), EndDate = new DateTime(2017,12,21)},
new Project{Id = "Object 3", BeginDate = new DateTime(2017,10,25), EndDate = new DateTime(2017,12,01)},
new Project{Id = "Object 4", BeginDate = new DateTime(2017,09,17), EndDate = new DateTime(2017,10,25)},
new Project{Id = "Object 5", BeginDate = new DateTime(2017,08,01), EndDate = new DateTime(2017,09,02)},
new Project{Id = "Object 6", BeginDate = new DateTime(2017,06,25), EndDate = new DateTime(2017,07,26)},
new Project{Id = "Object 7", BeginDate = new DateTime(2017,04,20), EndDate = new DateTime(2017,06,25)},
};
var resultsList = new List<Project>();
var previousProject = new Project();
var currentProject = new Project();
foreach(var p in projectList.OrderBy(p => p.BeginDate))
{
if (string.IsNullOrEmpty(previousProject.Id))
{
previousProject = currentProject = p;
continue;
}
if (p.BeginDate.AddDays(-1)<=previousProject.EndDate)
{
currentProject.EndDate = p.EndDate;
previousProject = currentProject;
continue;
}
else
{
resultsList.Add(currentProject);
previousProject = currentProject = p;
}
}
resultsList.Add(currentProject);
foreach(var p in resultsList)
{
var endDate = p.EndDate?.ToString("yyyy-MM-dd");
Console.WriteLine("{0}\t{1}\t{2}", p.Id, p.BeginDate.ToString("yyyy-MM-dd"), ((string.IsNullOrEmpty(endDate))?"Null":endDate));
}
}
}
public class Project
{
public string Id { get; set; }
public DateTime BeginDate { get; set; }
public DateTime? EndDate { get; set; }
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.