Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/267.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.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# 如何在linq中加入连续的日期范围_C#_.net_Entity Framework_Linq_Lambda - Fatal编程技术网

C# 如何在linq中加入连续的日期范围

C# 如何在linq中加入连续的日期范围,c#,.net,entity-framework,linq,lambda,C#,.net,Entity Framework,Linq,Lambda,我有这些数据示例 projects startdate enddate prj A 01 Jan 2019 10 Feb 2019 prj B 29 Jan 2019 15 Mar 2019 prj C 21 Mar 2019 02 May 2019 prj D 07 May 2019 10 Jun 2019 prj E 11 Jun 2019 30 Jul 2019 我想使用linq lambda使列表对象中的每个项都包含

我有这些数据示例

projects   startdate    enddate
prj A      01 Jan 2019  10 Feb 2019
prj B      29 Jan 2019  15 Mar 2019
prj C      21 Mar 2019  02 May 2019
prj D      07 May 2019  10 Jun 2019
prj E      11 Jun 2019  30 Jul 2019
我想使用linq lambda使列表对象中的每个项都包含连续的项目列表 分组结果大致如下

[
   [prj A, prj B],
   [prj C],
   [prj D, prj E]
]
  • prj A和B分组是因为日期范围prj A与prj重叠 B
  • 由于enddate prj B和startdate prj C之间有空格,所以 prj C属于不同的组
  • prj D和E分组是因为起始日期 prj E是从enddate prj D开始的下一天
那么,如何使用linq lambda创建这样的分组呢?
谢谢

您不能通过Linq
GroupBy
它们,因为组中的每个项目在其他项目中可能没有公共分组键,或者找不到它,相反,两个邻居之间只存在一个公共键

var result=newlist();
var项目=新列表
{
新项目{Name=“prj A”,
startdate=新日期时间(2019,1,1),enddate=新日期时间(2019,2,10)},
新项目{Name=“prj B”,
startdate=新日期时间(2019,1,29),enddate=新日期时间(2019,3,15)},
新项目{Name=“prj C”,
startdate=新日期时间(2019,3,21),enddate=新日期时间(2019,5,2)},
新项目{Name=“prj D”,
startdate=新日期时间(2019,5,7),enddate=新日期时间(2019,6,10)},
新项目{Name=“prj E”,
startdate=新日期时间(2019,6,11),enddate=新日期时间(2019,7,30)}
};
projects=projects.OrderBy(x=>x.startdate.ToList();
对于(var i=0;i
您可以编写一个遵循LINQ风格的扩展方法
JoinBy
充当分析滞后函数。它需要一个
orderBy
keySelector
来确定要计算的相邻值。
join
用于决定何时可以连接相邻值

public static class LinqExtension
{
    public static IEnumerable<IEnumerable<TSource>> JoinBy<TSource, TOrderKey, TKey>(
        this IEnumerable<TSource> source,
        Func<TSource, TOrderKey> orderBy,
        Func<TSource, TKey> keySelector,
        Func<TKey, TKey, bool> join)
    {
        var results = new List<List<TSource>>();
        var orderedSource = new List<TSource>(source).OrderBy(orderBy).ToArray();

        if (orderedSource.Length > 0)
        {
            var group = new List<TSource> { orderedSource[0] };
            results.Add(group);
            if (orderedSource.Length > 1)
            {
                for (int i = 1; i < orderedSource.Length; i++)
                {
                    var lag = orderedSource[i - 1];
                    var current = orderedSource[i];
                    if (join(keySelector(lag), keySelector(current)))
                    {
                        group.Add(current);
                    }
                    else
                    {
                        group = new List<TSource> { current };
                        results.Add(group);
                    }
                }
            }
        }

        return results;
    }
}
公共静态类LinqExtension
{
公共静态IEnumerable JoinBy(
这是一个数不清的来源,
Func orderBy,
Func键选择器,
Func(连接)
{
var results=新列表();
var orderedSource=新列表(源).OrderBy(OrderBy.ToArray();
如果(orderedSource.Length>0)
{
var group=新列表{orderedSource[0]};
结果:添加(组);
如果(orderedSource.Length>1)
{
for(int i=1;i
…并使用它将相邻的项目组合在一起

public class Project
{
    public string Name { get; set; }
    public DateTime Begin { get; set; }
    public DateTime End { get; set; }
}

[TestMethod]
public void TestCase1()
{
    var projects = new List<Project>() {
          new Project { Name = "A", Begin = new DateTime(2000, 1, 1), End = new DateTime(2000, 12, 31) }
        , new Project { Name = "B", Begin = new DateTime(2001, 1, 1), End = new DateTime(2001, 12, 31) }
        , new Project { Name = "C", Begin = new DateTime(2010, 1, 1), End = new DateTime(2010, 12, 31) }
        , new Project { Name = "D", Begin = new DateTime(2010, 6, 1), End = new DateTime(2010, 7, 1) }
     };

    var grouped = projects.JoinBy(
        x => x.Begin,
        x => (begin: x.Begin, end: x.End),
        (x1, x2) => x2.begin <= x1.end.AddDays(1) && x1.begin <= x2.end.AddDays(1));

    var builder = new StringBuilder();
    foreach (var grp in grouped)
    {
        builder.AppendLine(string.Join(", ", grp.Select(x => x.Name)));
    }

    var rendered = builder.ToString();

    // rendered =>
    // A, B
    // C, D
}
公共类项目
{
公共字符串名称{get;set;}
公共日期时间开始{get;set;}
公共日期时间结束{get;set;}
}
[测试方法]
公共无效测试用例1()
{
var projects=新列表(){
新项目{Name=“A”,Begin=newdatetime(2000,1,1),End=newdatetime(2000,12,31)}
,新项目{Name=“B”,开始=新日期时间(2001,1,1),结束=新日期时间(2001,12,31)}
,新项目{Name=“C”,开始=新日期时间(2010,1,1),结束=新日期时间(2010,12,31)}
,新项目{Name=“D”,开始=新日期时间(2010,6,1),结束=新日期时间(2010,7,1)}
};
var group=projects.JoinBy(
x=>x.开始,
x=>(开始:x.开始,结束:x.结束),
(x1,x2)=>x2
//A,B
//C,D
}
编辑:来自注释的另一个测试用例

[TestMethod]
public void TestCase2_FromComments()
{
    var projects = new List<Project>() {
          new Project { Name = "A", Begin = new DateTime(2019, 4, 2), End = new DateTime(2019, 8, 17) }
        , new Project { Name = "B", Begin = new DateTime(2019, 6, 1), End = new DateTime(2019, 7, 1) }
     };

    var grouped = projects.JoinBy(
        x => x.Begin,
        x => (begin: x.Begin, end: x.End),
        (x1, x2) => x2.begin <= x1.end.AddDays(1) && x1.begin <= x2.end.AddDays(1));

    var builder = new StringBuilder();
    foreach (var grp in grouped)
    {
        builder.AppendLine(string.Join(", ", grp.Select(x => x.Name)));
    }

    var rendered = builder.ToString();

    // rendered =>
    // A, B
}
[TestMethod]
public void TestCase2_FromComments()
{
var projects=新列表(){
新项目{Name=“A”,开始=新日期时间(2019,4,2),结束=新日期时间(2019,8,17)}
,新项目{Name=“B”,开始=新日期时间(2019,6,1),结束=新日期时间(2019,7,1)}
};
var group=projects.JoinBy(
x=>x.开始,
x=>(开始:x.开始,结束:x.结束),
(x1,x2)=>x2
//A,B
}

使用APL扫描运算符的变体(如
聚合
,仅返回中间结果)处理项目对,您可以创建一个
GroupBy
,该运算符对项目对使用谓词lambda并创建组,只要其值为真:

public static class IenumerableExt {
    // TKey combineFn((TKey Key, T Value) prevKeyItem, T curItem)
    //      prevKeyItem.Key = Previous Key (initially, seedKey)
    //      prevKeyItem.Value = Previous Item
    //      curItem = Current Item
    //      returns TKey for Current Item
    public static IEnumerable<(TKey Key, T Value)> ScanToPairs<T, TKey>(this IEnumerable<T> src, TKey seedKey, Func<(TKey Key, T Value), T, TKey> combineFn) {
        using (var srce = src.GetEnumerator())
            if (srce.MoveNext()) {
                var prevkv = (seedKey, srce.Current);

                while (srce.MoveNext()) {
                    yield return prevkv;
                    prevkv = (combineFn(prevkv, srce.Current), srce.Current);
                }
                yield return prevkv;
            }
    }

    // bool testFn(T prevVal, T curVal)
    public static IEnumerable<IGrouping<int, T>> GroupPairsByWhile<T>(this IEnumerable<T> src, Func<T, T, bool> testFn) =>
        src.ScanToPairs(1, (kvp, cur) => testFn(kvp.Value, cur) ? kvp.Key : kvp.Key + 1)
           .GroupBy(kvp => kvp.Key, kvp => kvp.Value);
}
公共静态类IenumerableExt{
//TKey组合Fn((TKey,T值)prevKeyItem,T curItem)
//prevKeyItem.Key=上一个键(最初为种子键)
//prevKeyItem.Value=上一项
//curItem=当前项目
//返回当前项的TKey
公共静态IEnumerable ScanToPairs(此IEnumerable src、TKey seedKey、Func组合){
使用(var srce=src.GetEnumerator())
if(srce.MoveNext()){
var prevkv=(种子键,srce.电流);
while(srce.MoveNext()){
收益率,千伏;
prevkv=(组合Fn(prevkv,srce.电流),srce.电流);
}
收益率,千伏;
}
}
//bool testFn(T preval,T curVal)
公共静态IEnumerable GroupPairsByWhile(此IEnumerable src,Func testFn)=>
src.ScanToPairs(1,(kvp,cur)=>testFn(kvp.Value,cur)?kvp.Key:kvp.Key+1)
.GroupBy(kvp=>kvp.Key,kvp=>kvp.Value)
public static class IenumerableExt {
    // TKey combineFn((TKey Key, T Value) prevKeyItem, T curItem)
    //      prevKeyItem.Key = Previous Key (initially, seedKey)
    //      prevKeyItem.Value = Previous Item
    //      curItem = Current Item
    //      returns TKey for Current Item
    public static IEnumerable<(TKey Key, T Value)> ScanToPairs<T, TKey>(this IEnumerable<T> src, TKey seedKey, Func<(TKey Key, T Value), T, TKey> combineFn) {
        using (var srce = src.GetEnumerator())
            if (srce.MoveNext()) {
                var prevkv = (seedKey, srce.Current);

                while (srce.MoveNext()) {
                    yield return prevkv;
                    prevkv = (combineFn(prevkv, srce.Current), srce.Current);
                }
                yield return prevkv;
            }
    }

    // bool testFn(T prevVal, T curVal)
    public static IEnumerable<IGrouping<int, T>> GroupPairsByWhile<T>(this IEnumerable<T> src, Func<T, T, bool> testFn) =>
        src.ScanToPairs(1, (kvp, cur) => testFn(kvp.Value, cur) ? kvp.Key : kvp.Key + 1)
           .GroupBy(kvp => kvp.Key, kvp => kvp.Value);
}
var ans = projects.GroupPairsByWhile((prev,cur) => cur.startdate <= prev.enddate.AddDays(1));