ally一次只工作一次…SQL可能更好。我正在抓取一个不同的项目ID、StartDate、EndDate、Price、PriceType并用C#处理它。如果可能的话,在SQL中可能会更好。。。但我已经走了一条复杂的道路来回答我的问题。基本上,如果日期范围重
ally一次只工作一次…SQL可能更好。我正在抓取一个不同的项目ID、StartDate、EndDate、Price、PriceType并用C#处理它。如果可能的话,在SQL中可能会更好。。。但我已经走了一条复杂的道路来回答我的问题。基本上,如果日期范围重,c#,algorithm,date-range,C#,Algorithm,Date Range,ally一次只工作一次…SQL可能更好。我正在抓取一个不同的项目ID、StartDate、EndDate、Price、PriceType并用C#处理它。如果可能的话,在SQL中可能会更好。。。但我已经走了一条复杂的道路来回答我的问题。基本上,如果日期范围重叠或接触并且价格相同,我必须将它们组合在一起。我可以把它转换成Linq。答案取决于日期,不同的范围可以重叠。我想我喜欢这个解决方案。有一定的潜力。这看起来很有希望。。。试一试,但必须先做些改变。我会让你知道的。我一直在用我的例子来玩弄它,它与我
ally一次只工作一次…SQL可能更好。我正在抓取一个不同的
项目ID、StartDate、EndDate、Price、PriceType
并用C#处理它。如果可能的话,在SQL中可能会更好。。。但我已经走了一条复杂的道路来回答我的问题。基本上,如果日期范围重叠或接触并且价格相同,我必须将它们组合在一起。我可以把它转换成Linq。答案取决于日期,不同的范围可以重叠。我想我喜欢这个解决方案。有一定的潜力。这看起来很有希望。。。试一试,但必须先做些改变。我会让你知道的。我一直在用我的例子来玩弄它,它与我在原始帖子中寻找的结果略有不同。开始日期和结束日期之间需要有1天的间隔。这是返回的A:9/26/2016-12/1/2016,B:12/1/2016-12/31/2016,C:12/31/2016-12/31/2017
,其中A和C不正确。不确定我是否应该创建另一个方法来修复它,或者在这个方法中是否有可以更改的内容。。。我把它搞砸了。你可以使用EndDate=edges[I].AddDays(-1)
将范围的最后一天向后推一天。我确实试过了,它在实际上只有内部范围需要截止日期的情况下,每一个结束日期都会减少一天。返回:A:9/26/2016-11/30/2016,B:12/1/2016-12/30/2016,C:12/31/2016-12/30/2017
我正在修改这个,我真的认为这超出了我的理解。这适用于无限多个日期范围/价格还是仅适用于两个?@justiceorjustus仅适用于输入范围。请参阅range1.Concat(range2…)
,因此没有限制…我仍然不明白。我如何使用列表而不是单个变量来实现它?或者我自己的日期范围/价格清单?@justiceorjustus这是我所能做的。如果你发布你的数据结构,显示你如何表示日期范围和相关价格,我可以给出一个可能更清楚的答案…(我在你的帖子中没有看到任何代码,只是一个请求)我非常感谢你的帮助。我编辑以包含我的数据结构。实际上,我每个ItemId有3种类型的PromotType,但该属性可以忽略。我已经分别为每种类型的PromotType运行了它,所以它不会变得混乱。
A. 09/26/16 - 12/31/17 at $20.00
B. 12/01/16 - 12/31/16 at $18.00
A. 09/26/16 - 11/30/16 at $20.00
B. 12/01/16 - 12/31/16 at $18.00
C. 01/01/17 - 12/31/17 at $20.00
public class PromoResult
{
public int ItemId { get; set; }
public decimal PromoPrice { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int PromoType { get; set; } // can ignore this...
}
09/26/16 - 12/31/17 at $20.00
TBD:
12/01/16 - 12/31/16 at $18.00
09/26/16 - 11/30/16 at $20.00
12/01/16 - 12/31/16 at $18.00
TBD:
01/01/17 - 12/31/17 at $20.00
public class DatePrice
{
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public decimal Price { get; set; }
}
IList<DatePrice> list = new List<DatePrice>(); // populate your data from the source..
var lowestPriceItem = list.OrderBy(item => item.Price).First();
public static IEnumerable<PriceRecord> ReduceOverlaps(IEnumerable<PriceRecord> source)
{
// Get a list of all edges of date ranges
// edit, added OrderBy (!)
var edges = source.SelectMany(record => new[] { record.StartDate, record.EndDate }).OrderBy(d => d).ToArray();
// iterate over pairs of edges (i and i-1)
for (int i = 1; i < edges.Length; i++)
{
// select min price for range i-1, i
var price = source.Where(r => r.StartDate <= edges[i - 1] && r.EndDate >= edges[i]).Select(r => r.Price).Min();
// return a new record from i-1, i with price
yield return new PriceRecord() { StartDate = edges[i - 1], EndDate = edges[i], Price = price };
}
}
SELECT RI.ItemNmbr, RI.UnitPrice, RI.CasePrice
, RP.ProgramID
, Row_Number() OVER (PARTITION BY RI.ItemNmbr,
ORDER BY CASE WHEN RI.UnitPrice > 0
THEN RI.UnitPrice
ELSE 1000000 END ASC
, CASE WHEN RI.CasePrice > 0
THEN RI.CasePrice
ELSE 1000000 END ASC
, RP.EndDate DESC
, RP.BeginDate ASC
, RP.ProgramID ASC) AS RowNumBtl
, Row_Number() OVER (PARTITION BY RI.UnitPrice,
ORDER BY CASE WHEN RI.CasePrice > 0
THEN RI.CasePrice
ELSE 1000000 END ASC
, CASE WHEN RI.UnitPrice > 0
THEN RI.UnitPrice
ELSE 1000000 END ASC
, RP.EndDate DESC
, RP.BeginDate ASC
, RP.ProgramID ASC) AS RowNumCase
FROM RetailPriceProgramItem AS RI
INNER JOIN RetailPriceMaster AS RP
ON RP.ProgramType = RI.ProgramType AND RP.ProgramID = RI.ProgramID
WHERE RP.ProgramType='S'
AND RP.BeginDate <= @date AND RP.EndDate >= @date
AND RI.Active=1
List<PromoResult> promoResult = new List<PromoResult>()
{
new PromoResult() { PromoPrice=20, StartDate = new DateTime(2016, 9, 26),EndDate=new DateTime(2017, 12, 31)},
new PromoResult() { PromoPrice=18, StartDate = new DateTime(2016, 12, 1),EndDate=new DateTime(2016, 12, 31)}
};
var result = promoResult.SelectMany(x => DateRange(x.StartDate, x.EndDate, TimeSpan.FromDays(1))
.Select(y => new { promo = x, date = y }))
.GroupBy(x => x.date).Select(x => x.OrderBy(y => y.promo.PromoPrice).First())
.OrderBy(x=>x.date)
.ToList();
var final = result.GroupSequenceWhile((x, y) => x.promo.PromoPrice == y.promo.PromoPrice)
.Select(g => new { start = g.First().date, end = g.Last().date, price = g.First().promo.PromoPrice })
.ToList();
foreach (var r in final)
{
Console.WriteLine(r.price + "$ " + r.start.ToString("MM/dd/yy", CultureInfo.InvariantCulture) + " " + r.end.ToString("MM/dd/yy", CultureInfo.InvariantCulture));
}
20$ 09/26/16 11/30/16
18$ 12/01/16 12/31/16
20$ 01/01/17 12/31/17
IEnumerable<DateTime> DateRange(DateTime start, DateTime end, TimeSpan period)
{
for (var dt = start; dt <= end; dt = dt.Add(period))
{
yield return dt;
}
}
public static IEnumerable<IEnumerable<T>> GroupSequenceWhile<T>(this IEnumerable<T> seq, Func<T, T, bool> condition)
{
List<T> list = new List<T>();
using (var en = seq.GetEnumerator())
{
if (en.MoveNext())
{
var prev = en.Current;
list.Add(en.Current);
while (en.MoveNext())
{
if (condition(prev, en.Current))
{
list.Add(en.Current);
}
else
{
yield return list;
list = new List<T>();
list.Add(en.Current);
}
prev = en.Current;
}
if (list.Any())
yield return list;
}
}
}