Linq生成给定日期范围的缺失记录列表

时间:2012-08-01 08:34:13

标签: c# linq

说我有以下课程的列表:

public class Holding
{
  public string HoldingId{ get; set; }      
  public DateTime date { get; set; }
}

在给定的日期范围内,每天都需要持有。我需要能够生成该范围缺失的馆藏列表。

所以说我有以下数据需要检查2010年6月1日至2010年6月5日的范围:

HoldingId Date
1         01-06-2010
1         02-06-2010
1         04-06-2010
2         02-06-2010
2         03-06-2010
2         05-06-2010
3         03-06-2010

对于这组数据,缺少的资产将是:

HoldingId Date
1         03-06-2010
1         05-06-2010   
2         01-06-2010
2         04-06-2010    
3         01-06-2010
3         02-06-2010
3         04-06-2010
3         05-06-2010

我使用以下问题的答案生成了日期列表范围: Find missing dates for a given range

我不能完全理解如何从这里前进......我假设我需要通过HoldingId分组来生成一系列日期然后做range.Except(holdings.dates)或者其他什么为此。

使用Linq有没有人能很好地解决这个问题?

3 个答案:

答案 0 :(得分:2)

你应该怎么做才是对的;这是我得到的;

List<Holding> holdings = new List<Holding>();
holdings.Add(new Holding(){ date=Convert.ToDateTime("01-06-2010"), HoldingId = "1" });
holdings.Add(new Holding(){ date=Convert.ToDateTime("02-06-2010"), HoldingId = "1" });
holdings.Add(new Holding(){ date=Convert.ToDateTime("04-06-2010"), HoldingId = "1" });
holdings.Add(new Holding(){ date=Convert.ToDateTime("02-06-2010"), HoldingId = "2" });
holdings.Add(new Holding(){ date=Convert.ToDateTime("03-06-2010"), HoldingId = "2" });
holdings.Add(new Holding(){ date=Convert.ToDateTime("05-06-2010"), HoldingId = "2" });
holdings.Add(new Holding(){ date=Convert.ToDateTime("03-06-2010"), HoldingId = "3" });

List<DateTime> dateRange = new List<DateTime>();
dateRange.Add(Convert.ToDateTime("01-06-2010"));
dateRange.Add(Convert.ToDateTime("02-06-2010"));
dateRange.Add(Convert.ToDateTime("03-06-2010"));
dateRange.Add(Convert.ToDateTime("04-06-2010"));
dateRange.Add(Convert.ToDateTime("05-06-2010"));

Dictionary<string, List<DateTime>> missingHoldings = new Dictionary<string, List<DateTime>>();

foreach(var holdGrp in  holdings.GroupBy (h => h.HoldingId))
{
    var missingDates = dateRange.Except(holdGrp.Select(h => h.date)).ToList();
    missingHoldings.Add(holdGrp.Key, missingDates);
}

答案 1 :(得分:1)

另一种方法:

public static List<Holding> MissingHoldings(List<Holding> existingHoldings, DateTime startDate, DateTime endDate)
{
    var missingHoldings = new List<Holding>();
    var holdingIds = existingHoldings.Select(h => h.HoldingId).Distinct().ToList();
    var dates = new List<DateTime>();
    for (var current = startDate.Date; current <= endDate.Date; current = current.AddDays(1))
    {
        dates.Add(current);
    }

    foreach (var holdingId in holdingIds)
    {
        missingHoldings
            .AddRange(
                dates.Where(date => !existingHoldings.Any(h => h.HoldingId == holdingId && h.date == date))
                .Select(date => new Holding {HoldingId = holdingId, date = date}));
    }
    return missingHoldings;
}

答案 2 :(得分:1)

纯粹的Linq查询受 saj 的回答启发:

var missingHoldingsList =
 from h in holdings.GroupBy( h => h.HoldingId )
 from d in dateRange.Except( h.Select(x => x.date) ) 
 orderby h.Key, d
 select new Holding { date = d , HoldingId = h.Key };

saj 的无循环版本的回答:

var missingHoldingsDict = (
  from h in holdings.GroupBy(h => h.HoldingId)
  select new
  {
    key = h.Key,
    holdings = 
      from d in dateRange.Except(h.Select(x => x.date))
      select new Holding { date = d, HoldingId = h.Key }
  }
).ToDictionary(
  h => h.key,
  h => h.holdings.ToList()
);