12

how can we use groupped ranges for equal or greater than ?

var data = new[] {
    new { Id = 0, Price = 2 },
    new { Id = 1, Price = 10 },
    new { Id = 2, Price = 30 },
    new { Id = 3, Price = 50 },
    new { Id = 4, Price = 120 },
    new { Id = 5, Price = 200 },
    new { Id = 6, Price = 1024 },
};

var ranges = new[] { 10, 50, 100, 500 };
var grouped = data.GroupBy( x => ranges.FirstOrDefault( r => r > x.Price ) );

grouped ouput is 
price 10-50 -> 3 
price 50-100 -> 1 
price 100-500 -> 2 

Needed output is grouped by equal or greater than the range used

price >= 10 -> 6
price >= 50 -> 4
price >= 100 -> 3
price >= 500 -> 1
Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
stackCoder
  • 205
  • 1
  • 2
  • 13
  • `100 -> 2` should be `100 -> 3`, since you seem to use the Count of items having a price equal or greater than the range used. (You should try to clarify your question by the way, since nowhere you mention some sort of COUNT) – Francis P Dec 11 '12 at 20:46
  • @Francis P thanks .. i edited my post.. I need exactly Count of items having a price equal or greater than the range used. – stackCoder Dec 11 '12 at 21:09

2 Answers2

13
var grouped = ranges.Select(r => new { 
            Price = r, 
            Count = data.Where(x => x.Price >= r).Count() });

And another option (if you have huge data, then grouping is better than enumerating all data for each price group):

var priceGroups = data.GroupBy(x => ranges.FirstOrDefault(r => r > x.Price))
                      .Select(g => new { Price = g.Key, Count = g.Count() })
                      .ToList();

var grouped = ranges.Select(r => new
{
    Price = r,
    Count = priceGroups.Where(g => g.Price > r || g.Price == 0).Sum(g => g.Count)
});
Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
  • @cosmicgate I don't see any categories in your question. What is that? – Sergey Berezovskiy Dec 12 '12 at 10:17
  • @cosmicgate sorry, but new requirement invalidates current answers. I think it's better to create new question for that – Sergey Berezovskiy Dec 12 '12 at 10:27
  • @cosmicgate also I can give you a hint where to start from - I think you need composite key for grouping `data.GroupBy(x => new { x.cat, price = ranges.FirstOrDefault(r => r > x.Price) })`. Sorry again - don't have free time now to investigate your requirement more. If you will have difficulties, then just ask new question on SO - somebody will help you :) – Sergey Berezovskiy Dec 12 '12 at 10:39
1

Grouping partitions the source, each item is assigned to a single group.

What you have is a good start:

var data = new[] {
    new { Id = 0, Price = 2 },
    new { Id = 1, Price = 10 },
    new { Id = 2, Price = 30 },
    new { Id = 3, Price = 50 },
    new { Id = 4, Price = 120 },
    new { Id = 5, Price = 200 },
    new { Id = 6, Price = 1024 },
};

var ranges = new[] { 10, 50, 100, 500 };
var grouped = data.GroupBy( x => ranges.FirstOrDefault( r => r <= x.Price ) );

Follow it up with:

int soFar = 0;
Dictionary<int, int> counts = grouped.ToDictionary(g => g.Key, g => g.Count());
foreach(int key in counts.Keys.OrderByDescending(i => i))
{
  soFar += counts[key];
  counts[key] = soFar;
}

Or if you want to do it in one linq statement:

int soFar = 0;
var grouped = data
  .GroupBy( x => ranges.FirstOrDefault( r => r <= x.Price ) )
  .OrderByDescending(g => g.Key)
  .Select(g =>
  {
    soFar += g.Count();
    return new Tuple<int, int>(g.Key, soFar)
  });
Amy B
  • 108,202
  • 21
  • 135
  • 185