C# 获取数量缺货时的日期
试图弄清楚如何在LINQ C缺货时获得日期范围结果# 假设我有一个如下的表格结果C# 获取数量缺货时的日期,c#,linq,C#,Linq,试图弄清楚如何在LINQ C缺货时获得日期范围结果# 假设我有一个如下的表格结果 EventDate | Qty 2014-02-03 | 6 2014-02-04 | -1 2014-02-05 | -2 2014-02-06 | 2 2014-02-07 | -1 2014-02-08 | -2 2014-02-09 | -3 2014-02-10 | 5 FromDate | ToDate 2014-02-04 | 2014-02-05 2014-02-07 | 2014-02-0
EventDate | Qty
2014-02-03 | 6
2014-02-04 | -1
2014-02-05 | -2
2014-02-06 | 2
2014-02-07 | -1
2014-02-08 | -2
2014-02-09 | -3
2014-02-10 | 5
FromDate | ToDate
2014-02-04 | 2014-02-05
2014-02-07 | 2014-02-09
现在我想得到一个日期范围,当库存中的数量为负0时,就像这样
EventDate | Qty
2014-02-03 | 6
2014-02-04 | -1
2014-02-05 | -2
2014-02-06 | 2
2014-02-07 | -1
2014-02-08 | -2
2014-02-09 | -3
2014-02-10 | 5
FromDate | ToDate
2014-02-04 | 2014-02-05
2014-02-07 | 2014-02-09
有人能帮我怎么做到吗
更新
我知道我可以通过将查询相乘来实现这一点,但如果可能的话,我希望只在一个LINQ查询中实现这一点。您可以编写自己的自定义函数来更改为LINQ表达式
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication
{
public class Class1
{
public static void Main(string[] args)
{
IEnumerable<QuantityDate> quantityDates = GetQuantityDates();//I'm sure you already have some way of retrieving these, via EF or Linq to SQL etc.
var results = quantityDates.Where(qd => qd.Qty < 0).CombineResults(); //This is the main Linq expression
foreach (var result in results)
{
Console.WriteLine("From Date: {0} To Date: {1}", result.FromDate, result.ToDate);
}
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
//Just to see the data for the moment. You'll probably get this data via EF or Linq to SQL
public static List<QuantityDate> GetQuantityDates()
{
List<QuantityDate> seed = new List<QuantityDate>()
{
new QuantityDate() { EventDate = new DateTime(2014, 2, 3), Qty = 6 },
new QuantityDate() { EventDate = new DateTime(2014, 2, 4), Qty = -1 },
new QuantityDate() { EventDate = new DateTime(2014, 2, 5), Qty = -2 },
new QuantityDate() { EventDate = new DateTime(2014, 2, 6), Qty = 2 },
new QuantityDate() { EventDate = new DateTime(2014, 2, 7), Qty = -1 },
new QuantityDate() { EventDate = new DateTime(2014, 2, 8), Qty = -2 },
new QuantityDate() { EventDate = new DateTime(2014, 2, 9), Qty = -3 },
new QuantityDate() { EventDate = new DateTime(2014, 2, 10), Qty = 5 }
};
return seed;
}
}
public static class Extensions
{
//This is where the magic happens, and we combine the results
public static List<OutOfStockRange> CombineResults(this IEnumerable<QuantityDate> input)
{
List<OutOfStockRange> output=new List<OutOfStockRange>();
OutOfStockRange lastEntered = null;
foreach(var qd in input.OrderBy(qd => qd.EventDate))
{
if(lastEntered != null && lastEntered.ToDate.AddDays(1) == qd.EventDate)
{
lastEntered.ToDate = qd.EventDate;
}
else
{
lastEntered =new OutOfStockRange(){FromDate = qd.EventDate, ToDate = qd.EventDate};
output.Add(lastEntered);
}
}
return output;
}
}
//This class represents the input data
public class QuantityDate
{
public DateTime EventDate { get; set; }
public int Qty { get; set; }
}
//This class represents the output data
public class OutOfStockRange
{
public DateTime FromDate { get; set; }
public DateTime ToDate { get; set; }
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
命名空间控制台应用程序
{
公共班级1
{
公共静态void Main(字符串[]args)
{
IEnumerable quantityDates=GetQuantityDates();//我确信您已经有了通过EF或Linq to SQL等检索这些数据的方法。
var results=quantityDates.Where(qd=>qd.qy<0).CombineResults();//这是主Linq表达式
foreach(结果中的var结果)
{
WriteLine(“从日期:{0}到日期:{1}”,result.FromDate,result.ToDate);
}
控制台。WriteLine(“按任意键退出”);
Console.ReadKey();
}
//现在只需查看数据。您可能会通过EF或LINQtoSQL获取此数据
公共静态列表GetQuantityDates()
{
列表种子=新列表()
{
new QuantityDate(){EventDate=new DateTime(2014,2,3),Quantity=6},
new QuantityDate(){EventDate=new DateTime(2014,2,4),Quantity=-1},
new QuantityDate(){EventDate=new DateTime(2014,2,5),Quantity=-2},
new QuantityDate(){EventDate=new DateTime(2014,2,6),Quantity=2},
new QuantityDate(){EventDate=new DateTime(2014,2,7),Quantity=-1},
new QuantityDate(){EventDate=new DateTime(2014,2,8),Quantity=-2},
new QuantityDate(){EventDate=new DateTime(2014,2,9),Quantity=-3},
new QuantityDate(){EventDate=new DateTime(2014,2,10),Quantity=5}
};
返回种子;
}
}
公共静态类扩展
{
//这就是神奇发生的地方,我们结合了结果
公共静态列表组合结果(此IEnumerable输入)
{
列表输出=新列表();
OutOfStockRange lastEntered=null;
foreach(input.OrderBy中的var qd(qd=>qd.EventDate))
{
if(lastEntered!=null&&lastEntered.ToDate.AddDays(1)==qd.EventDate)
{
lastEntered.ToDate=qd.EventDate;
}
其他的
{
lastEntered=new OutOfStockRange(){FromDate=qd.EventDate,ToDate=qd.EventDate};
输出。添加(上次输入);
}
}
返回输出;
}
}
//此类表示输入数据
公共类QuantityDate
{
公共日期时间事件日期{get;set;}
公共整数数量{get;set;}
}
//此类表示输出数据
公共类超出库存范围
{
公共日期时间FromDate{get;set;}
公共日期时间ToDate{get;set;}
}
}
对于仅使用内置函数的替代方案
这里的策略是选择数量小于零的所有日期,并针对这些日期中的每一个,执行子查询,以构建当前日期之后数量也小于零的所有日期的列表。使用TakeWhile
,这将在下一个日期之前停止,且数量为非负数。然后取其中的最大值,该值适用于范围的结束日期。最后一步是GroupBy
,删除映射到同一结束日期的“缺货”范围开始后的所有天数,为您留下一个不同的缺货日期范围
如下所示,它依赖于输入时按时间顺序排序的库存水平
public class StockLevel
{
public DateTime Date { get; set; }
public int Quantity { get; set; }
}
static void Main(string[] args)
{
List<StockLevel> stockLevels = new List<StockLevel>()
{
new StockLevel() { Date = DateTime.Parse("03-Feb-2014"), Quantity = 6 },
new StockLevel() { Date = DateTime.Parse("04-Feb-2014"), Quantity = -1 },
new StockLevel() { Date = DateTime.Parse("05-Feb-2014"), Quantity = -2 },
new StockLevel() { Date = DateTime.Parse("06-Feb-2014"), Quantity = 2 },
new StockLevel() { Date = DateTime.Parse("07-Feb-2014"), Quantity = -1 },
new StockLevel() { Date = DateTime.Parse("08-Feb-2014"), Quantity = -2 },
new StockLevel() { Date = DateTime.Parse("09-Feb-2014"), Quantity = -3 },
new StockLevel() { Date = DateTime.Parse("10-Feb-2014"), Quantity = 5 },
};
var outOfStockDates = stockLevels
.Where(a => a.Quantity < 0)
.Select(a => new
{
S1 = a.Date,
S2 = stockLevels
.Where(c => c.Date >= a.Date)
.TakeWhile(b => b.Quantity < 0)
.Select(b => b.Date).Max()
})
.GroupBy(a => a.S2, a => a.S1, (S2, S1S) => new { FromDate = S1S.Min(), ToDate = S2 });
Console.ReadKey();
}
公共类库存级别
{
公共日期时间日期{get;set;}
公共整数数量{get;set;}
}
静态void Main(字符串[]参数)
{
列表库存级别=新列表()
{
new StockLevel(){Date=DateTime.Parse(“2014年2月3日”),Quantity=6},
new StockLevel(){Date=DateTime.Parse(“2014年2月4日”),数量=-1},
new StockLevel(){Date=DateTime.Parse(“2014年2月5日”),数量=-2},
new StockLevel(){Date=DateTime.Parse(“2014年2月6日”),Quantity=2},
new StockLevel(){Date=DateTime.Parse(“2014年2月7日”),数量=-1},
new StockLevel(){Date=DateTime.Parse(“2014年2月8日”),数量=-2},
new StockLevel(){Date=DateTime.Parse(“2014年2月9日”),数量=-3},
new StockLevel(){Date=DateTime.Parse(“2014年2月10日”),Quantity=5},
};
var outOfStockDates=库存水平
.式中(a=>a.数量<0)
.选择(a=>新建
{
S1=a.日期,
S2=库存水平
.其中(c=>c.日期>=a.日期)
.TakeWhile(b=>b.数量<0)
.Select(b=>b.Date).Max()
})
.GroupBy(a=>a.S2,a=>a.S1,(S2,S1S)=>new{FromDate=S1S.Min(),ToDate=S2});
Console.ReadKey();
}
以下是我的做法
从您的数据开始:
var stockQuantities = new []
{
new { Date = new DateTime(2014, 2, 3), Qty = 6 },
new { Date = new DateTime(2014, 2, 4), Qty = -1 },
new { Date = new DateTime(2014, 2, 5), Qty = -2 },
new { Date = new DateTime(2014, 2, 6), Qty = 2 },
new { Date = new DateTime(2014, 2, 7), Qty = -1 },
new { Date = new DateTime(2014, 2, 8), Qty = -2 },
new { Date = new DateTime(2014, 2, 9), Qty = -3 },
new { Date = new DateTime(2014, 2, 10), Qty = 5 },
};
然后查询缺货记录:
var outOfStock = stockQuantities.Where(x => x.Qty < 0);
这是我得到的结果:
我想到了以下几点:
var src_objects = new []
{
new {date = DateTime.Parse("2014-02-03"), qty = 6},
new {date = DateTime.Parse("2014-02-04"), qty = -1},
new {date = DateTime.Parse("2014-02-05"), qty = -2},
new {date = DateTime.Parse("2014-02-06"), qty = 2},
new {date = DateTime.Parse("2014-02-07"), qty = -1},
new {date = DateTime.Parse("2014-02-08"), qty = -2},
new {date = DateTime.Parse("2014-02-09"), qty = -3},
new {date = DateTime.Parse("2014-02-10"), qty = 5}
};
int i = 0;
var ranges = src_objects
.OrderBy(key => key.date)
.Select(obj =>
{
if (obj.qty > 0)
{
++i;
return new { date = obj.date, group_key = 0 };
}
else
return new { date = obj.date, group_key = i };
})
.Where(obj => obj.group_key != 0)
.GroupBy(obj => obj.group_key)
.Select(g => new { fromdate = g.First().date, todate = g.Last().date });
ranges
.ToList()
.ForEach(range => Console.WriteLine(string.Format("{0} - {1}", range.fromdate, range.todate.Date)));
如果你把问题分成几个小部分,那就不太难了。首先获取数量为负数的日期(Linq的
.where()
函数),然后将结果传递给一个自定义函数,其中返回类型为List
,并具有一个类