如何将这些数据组织到我想要的LINQ对象中?

时间:2009-07-02 18:36:33

标签: c# linq linq-to-sql linq-to-objects

我有一个以下的类我正在尝试使用我查询的一堆数据创建一个列表:

public class Agency
{
    public string AgencyName { get; set; }
    public int AgencyID { get; set; }
    public IEnumerable<AuditRule> rules { get; set; } 
}

“AuditRule”在哪里:

public class AuditRule
{
    public int AuditRuleID { get; set; }
    public string AuditRuleName { get; set }
    public int AvgDaysWorked { get; set; }
}

现在,在一个相当复杂的查询之后,我已经能够将我的数据放入一个看起来像这样的匿名对象:

{ DateImported, AgencyID, AgencyName, AuditRuleName, AuditRuleID, DaysWorked }

我有这种格式的数千条记录,我正在尝试构建一个IEnumerable <Agency&gt;它本身将包含每个机构的规则列表。

因此,请以下列数据为例:

{ AgencyID = 1, AgencyName = "CCR", AuditRuleName = "Call", AuditRuleID = 1, DaysWorked = 3 }  
{ AgencyID = 1, AgencyName = "CCR", AuditRuleName = "Call", AuditRuleID = 1, DaysWorked = 5 }  
{ AgencyID = 1, AgencyName = "CCR", AuditRuleName = "Time", AuditRuleID = 2, DaysWorked = 2 }  
{ AgencyID = 2, AgencyName = "YRX", AuditRuleName = "Call", AuditRuleID = 1, DaysWorked = 3 }  
{ AgencyID = 2, AgencyName = "YRX", AuditRuleName = "Acct", AuditRuleID = 3, DaysWorked = 2 }

因此,在这些数据中,我试图首先构建一个代理列表(顶层的类),这个例子显然是“CCR”和“YRX”。然后,对于每个机构,我想在其IEnumerable <AuditRule&gt;中为每个规则输入一个条目。有记录。

因此,代理商“CCR”将有2个规则条目,“呼叫”和“时间”。 “Call”AuditRule条目的AvgDaysWorked为4,因为我们将代理商“CCR”下的“Call”条目平均为3天5天。 Time AuditRule条目的AvgDaysWorked为2,因为只有一个条目。

拥有一些LINQ忍者技能的人可以帮助我将这些数据纠缠到每个机构的代理商和规则列表中(该规则/代理商组合的平均天数)?

对我来说,即使能够将匿名对象聚集在一起也很复杂,我真的很难写这个查询来创建这个代理/ AuditRules列表。

我是否会使用SelectMany()或类似的东西?我有点迷失在这里。

2 个答案:

答案 0 :(得分:9)

我希望这能完成这项工作。

// GetAnonymousCollection() is hard to define... ;)
var anonymous = GetAnonymousCollection();

IEnumerable<Agency> result = anonymous
    .GroupBy(a => a.AgencyID)
    .Select(ag => new Agency()
    {
        AgencyID = ag.Key,
        AgencyName = ag.First().AgencyName,
        Rules = ag
            .GroupBy(agr => agr.AudiRuleID)
            .Select(agrg => new AuditRule()
            {
                AuditRuleID = agrg.Key,
                AuditRuleName = agrg.First().AuditRuleName,
                AvgDaysWorked = (Int32)agrg.Average(agrgr => agrgr.DaysWorked)
            })
      });

顺便说一句,考虑在平均时间内使用小数或浮点数。

答案 1 :(得分:6)

编辑:我认为我个人更喜欢丹尼尔在简单性方面的解决方案,虽然我的效率略高一些(因为它不需要通过调用First()多次评估查询来获得代理/审计规则名称)。我不完全确定如何处理我的答案:它显示了一些不同的东西(通过复合键分组),这很好,但同时它是一个庞大而笨拙的代码。再说一遍,这是一个完整的例子,它可以更容易地玩......

想法,有人吗?我应该把它留在这里,还是删掉它?


好的,我认为这可以满足您的需求。虽然这很邪恶。我没有时间立即解释,但GroupBy方法是至关重要的。

我已经格式化了一下,但它仍然不理想......

using System;
using System.Collections.Generic;
using System.Linq;

public class Agency
{
    public string AgencyName { get; set; }
    public int AgencyID { get; set; }
    public IEnumerable<AuditRule> Rules { get; set; } 

    public override string ToString()
    {
        return string.Format("Agency {0}/{1}:\r\n{2}",
            AgencyID, AgencyName,
            string.Concat(Rules.Select(x => x.ToString() + "\r\n")
                               .ToArray()));
    }
}

public class AuditRule
{
    public int AuditRuleID { get; set; }
    public string AuditRuleName { get; set; }
    public int AvgDaysWorked { get; set; }

    public override string ToString()
    {
        return string.Format("Audit rule {0}/{1}: {2}", AuditRuleID,
                             AuditRuleName, AvgDaysWorked);
    }
}

class Test
{    
    static void Main()
    {
        var previousQuery = new[]
        {
            new { AgencyID = 1, AgencyName = "CCR",
                  AuditRuleName = "Call",  AuditRuleID = 1, DaysWorked = 3 },
            new { AgencyID = 1, AgencyName = "CCR",
                  AuditRuleName = "Call", AuditRuleID = 1, DaysWorked = 5 },
            new { AgencyID = 1, AgencyName = "CCR",
                  AuditRuleName = "Time", AuditRuleID = 2, DaysWorked = 2 },
            new { AgencyID = 2, AgencyName = "YRX",
                  AuditRuleName = "Call", AuditRuleID = 1, DaysWorked = 3 },
            new { AgencyID = 2, AgencyName = "YRX",
                  AuditRuleName = "Acct", AuditRuleID = 3, DaysWorked = 2 },
        };

        var itemsGroupedByAgency = previousQuery.GroupBy
            (item => new { item.AgencyID, item.AgencyName });

        // Want to do the query for each group
        var query = itemsGroupedByAgency.Select
        // Outdented to avoid scrolling
        (group => new Agency 
         { 
             AgencyName = group.Key.AgencyName,
             AgencyID = group.Key.AgencyID,
             Rules = group.GroupBy(item => new { item.AuditRuleName, 
                                                 item.AuditRuleID },
                                                 (key, items) => new AuditRule
                    // Outdented to avoid scrolling :)
                    {
                       AuditRuleID = key.AuditRuleID,
                       AuditRuleName = key.AuditRuleName,
                       AvgDaysWorked = (int) items.Average(x => x.DaysWorked)
                    })
         });

        foreach (var item in query)
        {
            Console.WriteLine(item);
        }
    }
}