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

Kin*_*tor 2 c# linq linq-to-objects linq-to-sql

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

public class Agency
{
    public string AgencyName { get; set; }
    public int AgencyID { get; set; }
    public IEnumerable<AuditRule> rules { get; set; } 
}
Run Code Online (Sandbox Code Playgroud)

"AuditRule"在哪里:

public class AuditRule
{
    public int AuditRuleID { get; set; }
    public string AuditRuleName { get; set }
    public int AvgDaysWorked { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

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

{ DateImported, AgencyID, AgencyName, AuditRuleName, AuditRuleID, DaysWorked }
Run Code Online (Sandbox Code Playgroud)

我有这种格式的数千条记录,我正在尝试构建一个IEnumerable <Agency>,它本身包含每个代理的规则列表.

因此,以下面的数据为例:

{ 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 }
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

Dan*_*ner 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)
            })
      });
Run Code Online (Sandbox Code Playgroud)

顺便说一下,考虑使用小数或浮点数来表示平均时间.


Jon*_*eet 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)