简体   繁体   English

通过C#中的DateTime值合并对象

[英]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 在这里,您可以在这里找到我的示例

Model 模型

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")}";
    }
}

Method 方法

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;
}

Sample 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM