3

次のようなデータセットがあります。

[
{
 "Size" : "Small",
 "Details" :
  {
    "Detail 1" : 1.0,
    "Detail 1" : 1.0,
    "Detail 2" : 1.0,
  }
},
{
 "Size" : "Small",
 "Details" :
  {
    "Detail 1" : 2.0,
    "Detail 1" : 3.0,
    "Detail 2" : 4.0,
  }
},
{
 "Size" : "Medium",
 "Details" :
  {
    "Detail 1" : 1.0,
    "Detail 1" : 1.0,
    "Detail 2" : 1.0,
    "Detail 3" : 1.0,
  }
},
//... etc
]

同じ「サイズ」のすべてのアイテムについて、一致する「詳細」エントリを個別に合計し、「サイズ」のアイテムのようにそれらを平均したいと思います。すなわち:

[
{
 "Size" : "Small",
 "Details" :
 {
    "Detail 1" : 3.5,
    "Detail 2" : 2.5,     // Average of the summation of the two 'small' items in original data set
 },
    {
     "Size" : "Medium",
     "Details" :
      {
        "Detail 1" : 2.0, // Average of the two details for medium.
        "Detail 2" : 1.0,
        "Detail 3" : 1.0,
      }
    },
]

私が持っているコードはそのようなものですが、ネストされたセット全体で平均化する方法を見つけ出すのに苦労しています。任意のポインタをいただければ幸いです。

これまでの私のコード。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Test
{

    class ItemWithDetails
    {
        public string Size;
        public List<KeyValuePair<string, double>> Details { get; private set; }

        public ItemWithDetails(string size)
        {
            Size = size;
            Details.Add(new KeyValuePair<string, double>("Detail 1", 1));
            Details.Add(new KeyValuePair<string, double>("Detail 1", 1));
            Details.Add(new KeyValuePair<string, double>("Detail 2", 1));
            Details.Add(new KeyValuePair<string, double>("Detail 2", 1));
            Details.Add(new KeyValuePair<string, double>("Detail 2", 1));
            Details.Add(new KeyValuePair<string, double>("Detail 3", 1));

            if (size == "Large")
            {
                Details.Add(new KeyValuePair<string, double>("Detail 3", 1));
                Details.Add(new KeyValuePair<string, double>("Detail 3", 1));
                Details.Add(new KeyValuePair<string, double>("Detail 3", 1));
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var testData = new List<ItemWithDetails>()
            {
                new ItemWithDetails("Small"),
                new ItemWithDetails("Small"),
                new ItemWithDetails("Medium"),
                new ItemWithDetails("Medium"),
                new ItemWithDetails("Medium"),
                new ItemWithDetails("Large"),
                new ItemWithDetails("Large"),
                new ItemWithDetails("Large"),
            };

            // Trying to get the average of each detail, per size.

            var detailSummed = from item in testData
                               select new
                               {
                                   size = item.Size,
                                   detailsSummed = from detail in item.Details
                                                   group detail by detail.Key into detailGroup
                                                   select new
                                                   {
                                                       detailName = detailGroup.Key,
                                                       detailSum = detailGroup.Sum(a => (a.Value))
                                                   }
                               };

            var averageAcrossItems =    from item in detailSummed
                                        group item by item.size into itemGroup
                                        select new 
                                        {
                                            size = itemGroup.Key,
                                            detailsAveraged = // not sure how I can average across items, while at this level.  Do I have to flatten it?
                                        }

        }
    }
}

アップデート:

Adam Mills のコードを使用して、2 つの個別の LINQ クエリを組み合わせることで、さらに近づけることができました。これを、より読みやすい 1 つの LINQ クエリにすることはできますか?

        var detailSummed = from item in testData
                           select new
                           {
                               size = item.Size,
                               detailsSummed = from detail in item.Details
                                               group detail by detail.Key into detailGroup
                                               select new
                                               {
                                                   detailName = detailGroup.Key,
                                                   detailSum = detailGroup.Sum(a => (a.Value))
                                               }
                           };

        var test2 = detailSummed.GroupBy(x => x.size)
                                .Select(y =>
                                           new
                                           {
                                               Size = y.Key,
                                               DetailAverages = y   .SelectMany(x => x.detailsSummed)
                                                                    .GroupBy(x => x.detailName)
                                                                    .Select(x => new KeyValuePair<string, double>(x.Key, x.Average(c => c.detailSum)))
                                           });
4

5 に答える 5

2
 items.GroupBy(x => x.Size)
                .Select(y =>

                        new
                            {
                                Size = y.Key,
                                Details = y.SelectMany(x => x.Details)
                                            .GroupBy(x => x.Key)
                                            .Select(x => new
                                                             {
                                                                 Key = x.Key,
                                                                 Average = x.Average(c => c.Value),
                                                                 Sum = x.Sum(c => c.Value)
                                                             })
                            });
于 2012-11-13T15:16:06.990 に答える
1

detail1以下は、 の 2 つの値を合計することを除いて、入力を指定して目的の出力を生成しますmedium

var output = input
    .Select(iwd => new { Size = iwd.Size, Sums = iwd.Details.GroupBy(kvp => kvp.Key).Select(g => new { Detail = g.Key, Sum = g.Sum(kvp => kvp.Value) }) })
    .GroupBy(ds => ds.Size)
    .ToDictionary(g => g.Key, g => g.SelectMany(ds => ds.Sums).GroupBy(ds => ds.Detail).ToDictionary(dsg => dsg.Key, dsg => dsg.Sum(ds => ds.Sum) / g.Count()));

が生成されることに注意してくださいDictionary<string, Dictionary<string, int>>

于 2012-11-13T15:38:34.250 に答える
1

これはどう、

最初のセットアップ:

class ItemWithDetails {

    public string Size;
    public List<KeyValuePair<string, double>> Details { get; private set; }

    public ItemWithDetails() {
      Details=new List<KeyValuePair<string,double>>();
   }
}

そして、初期化するサンプル データ。

var testData = new ItemWithDetails[] {
    new ItemWithDetails { Size = "Small", 
        Details = { 
            new KeyValuePair<string,double>("Detail 1",1.0),
            new KeyValuePair<string,double>("Detail 1",1.0),
            new KeyValuePair<string,double>("Detail 2",1.0),
        }
    },
    new ItemWithDetails { Size="Small",
        Details = { 
            new KeyValuePair<string,double>("Detail 1",2.0),
            new KeyValuePair<string,double>("Detail 1",3.0),
            new KeyValuePair<string,double>("Detail 2",4.0),
        }
    },
    new ItemWithDetails { Size="Medium",

        Details = { 
            new KeyValuePair<string,double>("Detail 1",1.0),
            new KeyValuePair<string,double>("Detail 1",1.0),
            new KeyValuePair<string,double>("Detail 2",1.0),
            new KeyValuePair<string,double>("Detail 3",1.0),
        }
    },

};

これで、このクエリは必要な方法でデータを変換するはずです。

var q = from i in testData
        select new { 
             Size=i.Size,
             Details=i.Details
                     .GroupBy(d =>d.Key)
                     .Select(d=>new KeyValuePair<string,double>(d.Key,d.Sum(a=>a.Value)))
             } into x
        group x by x.Size into g
        let details = (
                       from a in g.SelectMany (b => b.Details)
                       group a by a.Key into g2
           select new KeyValuePair<string,double>(g2.Key,g2.Average(b=>b.Value))
                      )
       select new {
             Size=g.Key,
             Details=details
       };

そして、回答で kvp の代わりに匿名型を使用するだけで、もう少し読みやすくなります。

var q = from i in testData
        select new { 
             Size=i.Size,
             Details= (
                      from d in i.Details
                      group d by d.Key into g1
                      select new {Key=g1.Key,Value=g1.Sum(a=>a.Value)}
                      )

             } into x
        group x by x.Size into g
       select new {
             Size=g.Key,
             Details=(
                       from a in g.SelectMany (b => b.Details)
                       group a by a.Key into g2
           select new {Key =g2.Key, Value= g2.Average(b=>b.Value)}
                      )
       };
于 2012-11-13T15:44:55.077 に答える
0

これを試して:

var x =
    from item in testData
    group item by item.Size into sizeItems
    select new
    {
        Size = sizeItems.Key,
        Details =
            from item in sizeItems
            from detail in item.Details
            group detail by detail.Key into detailNumbers
            select new KeyValuePair<string, double>(detailNumbers.Key, detailNumbers.Sum(dn => dn.Value)) into detail
            group detail by detail.Key into detailNumbers
            select new KeyValuePair<string, double>(detailNumbers.Key, detailNumbers.Average(dn => dn.Value))
    };
于 2012-11-13T15:37:15.343 に答える
0
var detailSummed = testData
    .SelectMany(d => d.Details.GroupBy(de => de.Key).Select(de => new { Size = d.Size, DetailSize = de.Key, Sum = de.Sum(x => x.Value) } ))
    .GroupBy (d => d.Size)
    .Select (d => 
        new 
        { 
            Size = d.Key, 
            Details = d.GroupBy (x => x.DetailSize)
                .Select(x => 
                    new KeyValuePair<string, double>(x.Key, x.Average(xi => xi.Sum)))
                .ToList()
        });

これを分解しましょう:

d.Details.GroupBy(de => de.Key).Select(de => new { Size = d.Size, DetailSize = de.Key, Sum = de.Sum(x => x.Value) } )
テスト データから始めて、詳細をSize, DetailSize, Sum匿名型にグループ化します。これにより、 のさまざまなセットを区別できますItemWithDetails

.SelectMany(d => ...
これにより、リストのリスト (詳細) から、要約された値のフラット化されたリストに移動できます。

.GroupBy (d => d.Size)
これは、主要なアイテムのサイズによってグループ化されます。この時点で、これにより、要約されたデータがメインのサイズに属するすべての詳細にグループ化されます。このグループ化されたデータ セットに対して選択を実行します。

.Select (d => 
    new 
    { 
        Size = d.Key, 
        Details = d.GroupBy (x => x.DetailSize)
            .Select(x => new KeyValuePair<string, double>(x.Key, x.Average(xi => xi.Sum)))
            .ToList()
    });

この最後のメソッドは、要約された値をそれぞれの DetailSize に変換し、平均値を のリストに入れKeyValuePairます。

于 2012-11-13T16:41:33.080 に答える