使用LINQ填补数据空白的最佳方法

时间:2013-07-25 09:27:33

标签: c# linq

昨天我发布了以下问题,关于如何使用LINQ将具有多个级别的对象转换为平面结构中的“group”:

LINQ GroupBy on object with several levels

CédricBignon非常友好地回答了这个问题。我想要这个转换的原因是我可以使用userData变量填充ComponentArt的Silverlight XYChart组件。但是,我刚刚发现,当以堆叠条形式显示时,它们的组件存在已知错误。如果数据中存在空白,则无法正确显示,因此我需要确保所有用户都具有所有不同类别值的值。所以在我原来的问题中,我已经把我想要的userData填充了,我需要确保[User =“Bob”,Category =“International”,Spend = 0.00]也出现在结果

我通过在你给我的LINQ语句后使用以下代码实现了这一点:

// LINQ Statement provided by @Cedric 
var userData = from spend in allSpend
           from userDataPoint in
               (from monthSpend in spend.Spend
               from spendDetail in monthSpend.Detail
               group spendDetail by spendDetail.Description into g
               select new UserDataPoint
               {
                   User = spend.UserName,
                   Category = g.Key,
                   Spend = g.Sum(t => t.Amount)
               })
           select userDataPoint;
// END

List<UserDataPoint> userDataNoGaps = new List<UserDataPoint>();
userDataNoGaps = userData.ToList();
foreach (string strCategory in userData.Select(c => c.Category).Distinct())
{
    var existing = userData.Where(c => c.Category == strCategory).Select(c => c.User);
    userDataNoGaps.AddRange(userData.Where(c => !existing.Contains(c.User)).Select(c => new UserDataPoint() { User = c.User, Category = strCategory, Spend = 0 }));
}

但是当我有超过1000个用户和几个类别时,我的代码非常慢。这可以以某种方式纳入Cédric提供的LINQ语句中,或者我最好使用上面的代码填补空白?

1 个答案:

答案 0 :(得分:1)

您可以为所有用户/类别准备点数列表,其中0个值会将您的userData与union合并。

var userDataList = userData.ToList();

var usersList = userDataList.Select(x => x.Uder).Distinct().ToList();
var categoriesList = userDataList.Select(x => x.Category).Distinct().ToList();   

// make list of UserDataPoint with 0 sums
var empty = (from user in users
            from category in categoriesList 
            select new UserDataPoint
                       {
                          User = user,
                          Category = category,
                          Spend = 0
                       }).ToList();     

var merged = userDataList.Union(empty)
                         .GroupBy(x => new { x.User, x.Category }) // here sum up empty points with real
                         .Select(new UserDataPoint {
                             User = group.Key.User,
                             Category = group.Key.Category,
                             Spend = group.Sum(y => y.Spend)
                         }).ToList();