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