2

次のクラスがあり、クエリした一連のデータのリストを作成しようとしています:

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> を作成しようとしています。これには、各機関のルールのリストが含まれます。

したがって、例として次のデータを取り上げます。

{ 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」です。次に、機関ごとに<AuditRule、レコードがある IEnumerable > 内の各ルールのエントリが必要です。

したがって、エージェンシー「CCR」には、「Call」と「Time」という 2 つのルール エントリがあります。「Call」AuditRule エントリの AvgDaysWorked は 4 になります。これは、エージェンシー「CCR」の下にある「Call」のエントリを平均して 3 日と 5 日稼働しているためです。エントリが 1 つしかないため、Time AuditRule エントリの AvgDaysWorked は 2 になります。

LINQ忍者のスキルを持っている人が、このデータを各機関の機関とルールのリストにまとめるのを手伝ってくれませんか(そのルール/機関の組み合わせで働いた平均日数)?

その匿名オブジェクトをまとめることさえできるほど複雑で、このクエリを作成してこのエージェンシー/監査ルールのリストを作成するのに本当に苦労しています。

これは、SelectMany() などを使用するケースですか? 私はここでちょっと迷っています。

4

2 に答える 2

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

ちなみに、平均時間には小数または浮動小数点数を使用することを検討してください。

于 2009-07-02T18:56:48.643 に答える
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);
        }
    }
}
于 2009-07-02T19:04:29.517 に答える