3

Elementたとえば、 type の一般的なリストがあります。

public class Element
{
    public string Country { get; set; }
    public string City { get; set; }
    public int Population { get; set; }
}

以下のデータで。

var elements = new List<Element>
   {
       new Element { Country = "Country A", City = "Barrie", Population = 12 },
       new Element { Country = "Country A", City = "Barrie2", Population = 12 },
       new Element { Country = "Country A", City = "Barrie2", Population = 12 },
       new Element { Country = "Country A", City = "Barrie", Population = 12 },
       new Element { Country = "Country D", City = "Essex", Population = 12 },
       new Element { Country = "Country A", City = "Barrie", Population = 12 },
       new Element { Country = "Country A", City = "Barrie", Population = 12 },
       new Element { Country = "Country D", City = "Essex", Population = 12 },
       new Element { Country = "Country A", City = "Barrie", Population = 12 },
       new Element { Country = "Country A", City = "Barrie", Population = 12 }
   };

基本的に、国と都市ごとにグループ化された人口の累計が必要です。

何かのようなもの。

Country A | Barrie  | `running total for Barrie`
Country A | Barrie2 | `running total for Barrie2`
          |         | `total for Country A`
Country D | Essex   | `running total for Essex`
          |         | `total for Country D`
          |         | `total for everything`

どこにも拡張機能が見つからなかったので (ロールアップを数回使用する予定なので拡張機能と言いました)、試してみることにしました。そこで、この単純なクエリから始めました。

var groupedElements = elements
    .GroupBy(x => new { x.Country, x.City })
    .Select(x => new { Country = x.Key, City = x.Select(xx => xx.City), Population = x.Sum(xx => xx.Population) })
    .ToList();

このクエリは期待どおりに機能するので、正しい軌道に乗っていると思います。groupedElements次に、どのプロパティが集計されているかを把握する必要があると思います。これは、ロールアップを行う対象だからです。どうすればそれを達成できますか? または、集計関数を実行する列を指定するパラメーターを使用することもできます。

4

1 に答える 1

2

これはあなたが思うほど簡単ではないと思います。まず、必要な結果シーケンスのアイテムは、「当然」同じタイプではありません。各国の現在の合計、各国のグループ化された合計、そして全体の合計が必要です

この情報を作成するための簡潔なクエリを作成できたとしても、呼び出し元は、結果から各種類の合計を区別する必要があります。IEnumerable<XXX>そもそもあなたが望む結果をシングルとして見るのは理にかなっているのだろうか。このような優れたOOソリューションを作成し、そこから先に進む方がはるかに理にかなっているかもしれません。

public interface IGeographicEnity
{
   string Name { get; }
   int Population { get; }
}

public class City : IGeographicEntity {...}

public class Country : IGeographicEntity
{
   public IList<City> Cities { get {...} }       
   public int Population { get { return Cities.Sum(c => c.Population); } }
   ...
}

public class World : IGeographicEntity
{
    public IList<Country> Countries { get {...} }       
    public int Population { get { return Countries.Sum(c => c.Population); }
    ...
}

それでも元のアイデアに固執したい場合は、これが私が思いつくことができる最高のものです:

public class PopulationTotal
{
    // You can use subclassing instead of an enum to represent this
    public enum Kind
    { RunningTotalWithinCountry, TotalForCountry, TotalOverall }

    public string GroupName { get; private set; }
    public int Value { get; private set; }
    public Kind Kind { get; private set; }

    public static IEnumerable<PopulationTotal> GetTotals(IEnumerable<Element> elements)
    {
        int overallTotal = 0;

        foreach (var elementsByCountry in elements.GroupBy(e => e.Country))
        {
            int runningTotalForCountry = 0;

            foreach (var element in elementsByCountry)
            {
                runningTotalForCountry += element.Population;
                yield return new PopulationTotal
                                    {
                                        GroupName = element.City,
                                        Kind = Kind.RunningTotalWithinCountry,
                                        Value = runningTotalForCountry
                                    };
            }

            overallTotal += runningTotalForCountry;

            yield return new PopulationTotal
                                {
                                    GroupName = elementsByCountry.Key,
                                    Kind = Kind.TotalForCountry,
                                    Value = runningTotalForCountry
                                };
        }

        yield return new PopulationTotal
                            {
                                GroupName = null,
                                Kind = Kind.TotalOverall,
                                Value = overallTotal
                            };
    }
}

使用法

var totals = PopulationTotal.GetTotals(elements);
于 2010-10-29T03:16:43.817 に答える