使用C#中的LINQ在范围之间对数据进行分组

时间:2017-02-23 16:30:23

标签: c# asp.net asp.net-mvc linq group-by

我已经制作了以下代码来创建两个数字之间的范围,数据分为7列:

  private List<double> GetRangeForElements(double minPrice, double maxPrice)
        {
            double determineRange = Math.Round(maxPrice / 7.00d, 3);
            var ranges = new List<double>();
            ranges.Insert(0, Math.Round(minPrice, 3));
            ranges.Insert(1, determineRange);
            for (int i = 2; i < 8; i++)
            {
                ranges.Insert(i, Math.Round(determineRange * i, 3));
            }
            return ranges;
        }

现在,当我调用方法时,我有范围列表:

var ranges = GetRangeForElements(1,1500);

另一方面,我现在拥有包含以下数据(属性)的数据(列表):

public double TransactionPrice {get;set;}

public int SaleAmount {get;set;}

输入数据将是:

Transaction price    Sale amount

114.5                   4
331.5                   6
169.59                  8
695.99                  14
1222.56                 5

1到1500之间的生成范围是:

1
214.28
428.57
642.85
857.14
1071.43
1285.71
1500.00

所需的输出是:

Range                    Sales
(1 - 214.28)             12
(214.28 - 428.57)        6
(428.57 - 642.85)        0
(642.85 - 857.14)        14
(857.14 - 1071.43)       0 
(1071.43 - 1285.71)      5    
(1285.71 - 1500)         0

我尝试过这样的事情:

var priceGroups = _groupedItems.GroupBy(x => ranges.FirstOrDefault(r => r > x.TransactionPrice))
   .Select(g => new { Price = g.Key, Sales = g.Sum(x=>x.Sales) })
   .ToList();

但是这并没有给我我想要的东西,我收到的结果完全搞砸了(我能够手动验证数据和结果)......

有人能帮助我吗?

P.S。伙计们,没有销售的范围应该只是将值设置为0 ...

@blinkenknight这里是我所说的图片,最低价格= 2.45,最高价格= 2.45

,您发布的第二种方法的输出是:

enter image description here

1 个答案:

答案 0 :(得分:3)

由于GetRangeForElements会返回List<double>,因此您无法对其进行分组。但是,您可以按范围分组 index ,然后使用该索引获取范围:

var rangePairs = ranges.Select((r,i) => new {Range = r, Index = i}).ToList();
var priceGroups = _groupedItems
    .GroupBy(x => rangePairs.FirstOrDefault(r => r.Range >= x.TransactionPrice)?.Index ?? -1)
    .Select(g => new { Price = g.Key >= 0 ? rangePairs[g.Key].Range : g.Max(x => x.TransactionPrice), Sales = g.Sum(x=>x.Sales) })
    .ToList();

假设_groupedItems是一个列表,您也可以从范围开始,并直接生成结果:

var priceGroups = ranges.Select(r => new {
    Price = r
,   Sales = _groupedItems.Where(x=>ranges.FirstOrDefault(y=>y >= x.TransactionPrice) == r).Sum(x => x.Sales)
});

注意:很有可能,您的GetRangeForElements有错误:它假定minPricemaxPrice / 7.00d相比相对较小。要查看此问题,请考虑如果您通过minPrice=630maxPrice=700会发生什么:您将获得630, 100, 200, 300, ...而不是630, 640, 650, ...。要解决此问题,请计算(maxPrice - minPrice) / 7.00d并将其用作从minPrice开始的步骤:

 private List<double> GetRangeForElements(double minPrice, double maxPrice) {
     double step = (maxPrice - minPrice) / 7.0;
     return Enumerable.Range(0, 8).Select(i => minPrice + i*step).ToList();
 }