Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 合并连续日期期间_C#_Date - Fatal编程技术网

C# 合并连续日期期间

C# 合并连续日期期间,c#,date,C#,Date,我有一个日期周期列表,这些周期没有重叠 |StartDate| EndDate| | null | 1/12 | | 2/12 | null | | null | 4/12 | | 6/12 | 8/12 | | 9/12 | null | | null | 10/12 | | 11/12 | null | 我必须将这些期间合并到如下列表中: |StartDate| EndDate| | null | 1/12 | |

我有一个日期周期列表,这些周期没有重叠

|StartDate| EndDate|
| null    |  1/12  |
| 2/12    |  null  |
| null    |  4/12  |
| 6/12    |  8/12  |
| 9/12    |  null  |
| null    |  10/12 |
| 11/12   |  null  |
我必须将这些期间合并到如下列表中:

|StartDate| EndDate|
| null    |  1/12  |
| 2/12    |  4/12  |
| 6/12    |  8/12  |
| 9/12    |  10/12 |
| 11/12   |  null  |
这是我的解决方案,但我认为这不是一个明智的方法

        var dateList = periodList.SelectMany(x => new[] { 
            new {Date = x.Item1, type = "S"}, 
            new {Date = x.Item2, type = "E"} 
        }).Where(x => x.Date != null).OrderBy(x => x.Date).ToArray();

        var result = new List<Tuple<DateTime?, DateTime?>>();
        int i = 0;
        do
        {
            if (i == 0 && dateList[i].type == "E")
            {
                result.Add(new Tuple<DateTime?, DateTime?>(null, dateList[i].Date));
            }
            else if (i + 1 == dateList.Count() && dateList[i].type == "S")
            {
                result.Add(new Tuple<DateTime?, DateTime?>(dateList[i].Date, null));
            }
            else
            {
                if (dateList[i].type == "S" && dateList[i+1].type == "E")
                {
                    result.Add(new Tuple<DateTime?, DateTime?>(dateList[i].Date, dateList[i + 1].Date));
                    i++;
                }                    
            }
            i++;
        } while (i < dateList.Count());
var dateList=periodList.SelectMany(x=>new[]{
新建{Date=x.Item1,type=“S”},
新建{Date=x.Item2,type=“E”}
}).Where(x=>x.Date!=null).OrderBy(x=>x.Date).ToArray();
var result=新列表();
int i=0;
做
{
如果(i==0&&dateList[i]。类型==“E”)
{
Add(新元组(null,日期列表[i].Date));
}
else if(i+1==dateList.Count()&&dateList[i].type==S)
{
Add(新元组(dateList[i].Date,null));
}
其他的
{
如果(日期列表[i]。类型==“S”&&dateList[i+1]。类型==“E”)
{
添加(新元组(日期列表[i].Date,日期列表[i+1].Date));
i++;
}                    
}
i++;
}而(i
我的解决方案可能看起来更长,但我认为它更干净。我认为你有<强> > < <强> >类(而不是<代码> tuple < /代码>)如下:

public class Period
{
    public DateTime? StartDate { get; set; }
    public DateTime? EndDate { get; set; }
}
将日期添加到期间列表中:

//准备好句点列表
List periodList=//准备期间;
通过消除null开始日期和结束日期,分别获取开始日期和结束日期:

// Get start dates
List<DateTime> startDates = periodList
    .Where(p => p.StartDate.HasValue)
    .Select(p => p.StartDate.Value)
    .ToList();

// Get end dates
List<DateTime> endDates = periodList
    .Where(p => p.EndDate.HasValue)
    .Select(p => p.EndDate.Value)
    .ToList();
//获取开始日期
列表开始日期=周期列表
.Where(p=>p.StartDate.HasValue)
.Select(p=>p.StartDate.Value)
.ToList();
//获取结束日期
列表结束日期=周期列表
.Where(p=>p.EndDate.HasValue)
.Select(p=>p.EndDate.Value)
.ToList();
然后执行其他操作:

// Clear list of periods
periodList.Clear();

// Add start dates which are bigger than LAST end date with NULL end date period
startDates.Where(s => s > endDates.Max())
    .ToList()
    .ForEach(s => periodList.Add(new Period() { StartDate = s, EndDate = null }));

// Add end dates which are smaller than FIRST start date with NULL start date period
endDates.Where(e => e < startDates.Min())
    .ToList()
    .ForEach(e => periodList.Add(new Period() {StartDate = null, EndDate = e}));

// Match other dates and add them to list
startDates.Where(s => s < endDates.Max())
    .ToList()
    .ForEach(s => periodList.Add(new Period()
                                {
                                    StartDate = s,
                                    EndDate = endDates.Where(e => e > s).Min()
                                }));

// Oder period list
periodList = periodList.OrderBy(p => p.StartDate).ToList();
//清除句点列表
periodList.Clear();
//添加大于最后一个结束日期且结束日期期间为空的开始日期
其中(s=>s>endDates.Max())
托利斯先生()
.ForEach(s=>periodList.Add(newperiod(){StartDate=s,EndDate=null}));
//添加小于第一个开始日期且开始日期期间为空的结束日期
其中(e=>eperiodList.Add(newperiod(){StartDate=null,EndDate=e}));
//匹配其他日期并将其添加到列表中
其中(s=>speriodList.Add(新期间()
{
起始日期=s,
EndDate=endDates.Where(e=>e>s).Min()
}));
//订货周期表
periodList=periodList.OrderBy(p=>p.StartDate.ToList();
您可以测试.NETFiddle演示


我希望它会有所帮助。

下面的代码是一个使用

  • a
    日期范围
    类型和
  • 指定
    DateTime.MinValue
    DateTime.MaxValue
    的值,以“保护”任何
    null
    第一个开始日期或任何
    null
    最后一个结束日期
  • 下面是从两个可为空的
    DateTime
    值的平行列表中创建
    DateRange
    值列表的方法:

    public static List<DateRange> MakeRanges(List<DateTime?> list1, List<DateTime?> list2)
    {
        //Validate arguments to the function
        if (list1 == null || list2 == null || list1.Count == 0 ||
            list2.Count == 0 || list1.Count != list2.Count)
        {
            throw new ArgumentException("Bad arguments passed to MakeRanges().");
        }
        //If present, replace null start value of list1 with a sentinel
        list1[0] = list1[0] ?? DateTime.MinValue;
        //If present, replace null end value of list2 with a sentinel 
        list2[list2.Count - 1] = list2[list2.Count - 1] ?? DateTime.MaxValue;
    
        //this expression does the heavy lifting.  Match a start date with the closest non-null end-date
        return list1.Where(s => s.HasValue).Select( startItem => new DateRange{
                Start = startItem,
                End = list2.Find(e => (e.HasValue && (e > startItem.Value))).Value
            }).ToList();
    }
    
    下面是一个控制台应用程序主驱动程序:

    public static void Main(string[] args)
    {
        List<DateTime?> list1 = new List<DateTime?>() { null, DateTime.Parse("2014-02-12"), null, DateTime.Parse("2014-06-12"), DateTime.Parse("2014-09-12"), null, DateTime.Parse("2014-11-12")};
        List<DateTime?> list2 = new List<DateTime?>() { DateTime.Parse("2014-01-12"), null, DateTime.Parse("2014-04-12"), DateTime.Parse("2014-08-12"), null, DateTime.Parse("2014-10-12"), null };
    
        List<DateRange> ranges = MakeRanges(list1, list2);
    
        //Print out results
        foreach (var range in ranges)
        {
            Console.WriteLine(range);
        }
        var pressAKeyToExit = Console.ReadKey();
    }
    

    假设输入列表中的日期总是按顺序排列,下面是一个快速解决方案(不知道是否更快):

    使用系统;
    使用System.Collections.Generic;
    使用系统诊断;
    使用System.Linq;
    名称空间SO30229368
    {
    班级计划
    {
    私有常量字符串NullItem=“null”;
    静态void Main(字符串[]参数)
    {
    var periodList=新列表
    {
    新元组(NullItem,“1/12”),
    新元组(“2/12”,空项),
    新元组(NullItem,“4/12”),
    新元组(“6/12”、“8/12”),
    新元组(“9/12”,NullItem),
    新元组(NullItem,“10/12”),
    新元组(“11/12”,NullItem)
    };
    var ConcertiveList=GetConcertive(周期列表);
    foreach(连续列表中的变量tupleItem)
    WriteLine(“{0}-{1}”,tupleItem.Item1,tupleItem.Item2);
    Console.ReadLine();
    }
    私有静态IEnumerable GetContinuous(列表周期列表)
    {
    if(periodList==null)
    抛出新的ArgumentNullException(“periodList”);
    如果(periodList.Count==0)
    返回新列表();
    var startList=periodList.Select(x=>x.Item1).Where(y=>y!=NullItem.ToList();
    if(periodList.First().Item1==NullItem)
    插入(0,空项);
    var endList=periodList.Select(x=>x.Item2).Where(y=>y!=NullItem.ToList();
    if(periodList.Last().Item2==NullItem)
    endList.Add(空项);
    Assert(startList.Count==endList.Count);
    返回Enumerable.Zip(startList,endList,(start,end)=>newtuple(start,end)).ToList();
    }
    }
    }
    
    尽管正如其他人所建议的,但最好将对象建模为自定义对象(例如DateRange),而不是使用元组。

    如果您确定

    1) 日期间隔是有序的

    2) 每次
    null
    endDate之后,下一个开始日期将是
    null

    然后,一个简单的方法可能是删除所有中间
    null

    List<DateTime?> startDates = allStartDates();  // excluding null values, but including the first one.
    List<DateTime?> endDates = allEndDates();  // excluding null values, but including the last one.
    

    我建议您使用属性
    StartDate
    EndDate
    创建一些
    DateRange
    类,而不是使用具有无意义的
    Item1
    Item2
    属性的元组。您还可以创建方法,如
    Intersects
    检查时间范围是否相交,以及方法
    intersession
    从两个范围中获取新的时间范围
    public static void Main(string[] args)
    {
        List<DateTime?> list1 = new List<DateTime?>() { null, DateTime.Parse("2014-02-12"), null, DateTime.Parse("2014-06-12"), DateTime.Parse("2014-09-12"), null, DateTime.Parse("2014-11-12")};
        List<DateTime?> list2 = new List<DateTime?>() { DateTime.Parse("2014-01-12"), null, DateTime.Parse("2014-04-12"), DateTime.Parse("2014-08-12"), null, DateTime.Parse("2014-10-12"), null };
    
        List<DateRange> ranges = MakeRanges(list1, list2);
    
        //Print out results
        foreach (var range in ranges)
        {
            Console.WriteLine(range);
        }
        var pressAKeyToExit = Console.ReadKey();
    }
    
    null-1/12/2014
    2/12/2014-4/12/2014
    6/12/2014-8/12/2014
    9/12/2014-10/12/2014
    11/12/2014-null
    
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    
    namespace SO30229368
    {
        class Program
        {
            private const string NullItem = "null";
    
            static void Main(string[] args)
            {
                var periodList = new List<Tuple<string, string>>
                {
                    new Tuple<string, string>(NullItem, "1/12"),
                    new Tuple<string, string>("2/12", NullItem),
                    new Tuple<string, string>(NullItem, "4/12"),
                    new Tuple<string, string>("6/12", "8/12"),
                    new Tuple<string, string>("9/12", NullItem),
                    new Tuple<string, string>(NullItem, "10/12"),
                    new Tuple<string, string>("11/12", NullItem)
                };
    
                var consecutiveList = GetConsecutive(periodList);
                foreach (var tupleItem in consecutiveList)
                    Console.WriteLine("{0} - {1}", tupleItem.Item1, tupleItem.Item2);
    
                Console.ReadLine();
            }
    
            private static IEnumerable<Tuple<string, string>> GetConsecutive(List<Tuple<string, string>> periodList)
            {
                if (periodList == null)
                    throw new ArgumentNullException("periodList");
                if (periodList.Count == 0)
                    return new List<Tuple<string, string>>();
    
                var startList = periodList.Select(x => x.Item1).Where(y => y != NullItem).ToList();
                if (periodList.First().Item1 == NullItem)
                    startList.Insert(0, NullItem);
                var endList = periodList.Select(x => x.Item2).Where(y => y != NullItem).ToList();
                if (periodList.Last().Item2 == NullItem)
                    endList.Add(NullItem);
    
                Debug.Assert(startList.Count == endList.Count);
                return Enumerable.Zip(startList, endList, (start, end) => new Tuple<string, string>(start, end)).ToList();
            }
        }
    }
    
    List<DateTime?> startDates = allStartDates();  // excluding null values, but including the first one.
    List<DateTime?> endDates = allEndDates();  // excluding null values, but including the last one.
    
    DateTime? startDate3 = startDates[2];
    DateTime? endDate3 = endDates[2];